def cartesianProductExpander(childStructuralNode, view, depth, axisDisposition, facts, tblAxisRels, i): if i is not None: # recurse table relationships for cartesian product for j, tblRel in enumerate(tblAxisRels[i+1:]): tblObj = tblRel.toModelObject if isinstance(tblObj, (ModelEuAxisCoord, ModelDefinitionNode)) and axisDisposition == tblRel.axisDisposition: addBreakdownNode(view, axisDisposition, tblObj) #if tblObj.cardinalityAndDepth(childStructuralNode)[1] or axisDisposition == "z": if axisDisposition == "z": subOrdTblCntx = StructuralNode(childStructuralNode, tblObj, tblObj) subOrdTblCntx._choiceStructuralNodes = [] # this is a breakdwon node subOrdTblCntx.indent = 0 # separate breakdown not indented] depth = 0 # cartesian next z is also depth 0 childStructuralNode.childStructuralNodes.append(subOrdTblCntx) else: # non-ordinate composition subOrdTblCntx = childStructuralNode # predefined axes need facts sub-filtered if isinstance(childStructuralNode.definitionNode, ModelClosedDefinitionNode): matchingFacts = childStructuralNode.evaluate(childStructuralNode.definitionNode, childStructuralNode.definitionNode.filteredFacts, evalArgs=(facts,)) else: matchingFacts = facts # returns whether there were no structural node results subOrdTblCntx.abstract = True # can't be abstract across breakdown expandDefinition(view, subOrdTblCntx, tblObj, tblObj, depth, # depth + (0 if axisDisposition == 'z' else 1), axisDisposition, matchingFacts, j + i + 1, tblAxisRels) #cartesian product break
def cartesianProductExpander(childStructuralNode, view, depth, axisDisposition, facts, tblAxisRels, i): if i is not None: # recurse table relationships for cartesian product for j, tblRel in enumerate(tblAxisRels[i + 1:]): tblObj = tblRel.toModelObject if isinstance(tblObj, (ModelEuAxisCoord, ModelDefinitionNode )) and axisDisposition == tblRel.axisDisposition: #addBreakdownNode(view, axisDisposition, tblObj) #if tblObj.cardinalityAndDepth(childStructuralNode)[1] or axisDisposition == "z": if axisDisposition == "z": subOrdTblCntx = StructuralNode(childStructuralNode, tblObj, tblObj) subOrdTblCntx._choiceStructuralNodes = [ ] # this is a breakdwon node subOrdTblCntx.indent = 0 # separate breakdown not indented] depth = 0 # cartesian next z is also depth 0 childStructuralNode.childStructuredNodeList.append( subOrdTblCntx) else: # non-ordinate composition subOrdTblCntx = childStructuralNode # predefined axes need facts sub-filtered if isinstance(childStructuralNode.definitionNode, ModelClosedDefinitionNode): matchingFacts = childStructuralNode.evaluate( childStructuralNode.definitionNode, childStructuralNode.definitionNode.filteredFacts, evalArgs=(facts, )) else: matchingFacts = facts # returns whether there were no structural node results subOrdTblCntx.abstract = True # can't be abstract across breakdown expandDefinition( view, subOrdTblCntx, tblObj, tblObj, depth, # depth + (0 if axisDisposition == 'z' else 1), axisDisposition, matchingFacts, j + i + 1, tblAxisRels) #cartesian product break
def expandDefinition(view, structuralNode, breakdownNode, definitionNode, depth, axisDisposition, facts, i=None, tblAxisRels=None, processOpenDefinitionNode=True): subtreeRelationships = view.axisSubtreeRelSet.fromModelObject(definitionNode) def checkLabelWidth(structuralNode, checkBoundFact=False): if axisDisposition == "y": # messages can't be evaluated, just use the text portion of format string label = structuralNode.header(lang=view.lang, returnGenLabel=not checkBoundFact, returnMsgFormatString=not checkBoundFact) if label: # need to et more exact word length in screen units widestWordLen = max(len(w) * 16 for w in label.split()) # abstract only pertains to subtree of closed nodesbut not cartesian products or open nodes while structuralNode.depth >= len(view.rowHdrColWidth): view.rowHdrColWidth.append(0) if definitionNode.isAbstract or not subtreeRelationships: # isinstance(definitionNode, ModelOpenDefinitionNode): if widestWordLen > view.rowHdrColWidth[structuralNode.depth]: view.rowHdrColWidth[structuralNode.depth] = widestWordLen else: if widestWordLen > view.rowNonAbstractHdrSpanMin[structuralNode.depth]: view.rowNonAbstractHdrSpanMin[structuralNode.depth] = widestWordLen if structuralNode and isinstance(definitionNode, (ModelBreakdown, ModelEuAxisCoord, ModelDefinitionNode)): try: #cartesianProductNestedArgs = (view, depth, axisDisposition, facts, tblAxisRels, i) ordCardinality, ordDepth = definitionNode.cardinalityAndDepth(structuralNode) if (not definitionNode.isAbstract and isinstance(definitionNode, ModelClosedDefinitionNode) and ordCardinality == 0): view.modelXbrl.error("xbrlte:closedDefinitionNodeZeroCardinality", _("Closed definition node %(xlinkLabel)s does not contribute at least one structural node"), modelObject=(view.modelTable,definitionNode), xlinkLabel=definitionNode.xlinkLabel, axis=definitionNode.localName) nestedDepth = depth + ordDepth # HF test cartesianProductNestedArgs = [view, nestedDepth, axisDisposition, facts, tblAxisRels, i] if axisDisposition == "z": if depth == 1: # choices (combo boxes) don't add to z row count view.zAxisRows += 1 elif axisDisposition == "x": if ordDepth: if nestedDepth - 1 > view.colHdrRows: view.colHdrRows = nestedDepth - 1 ''' if not view.colHdrDocRow: if definitionNode.header(role="http://www.xbrl.org/2008/role/documentation", lang=view.lang): view.colHdrDocRow = True if not view.colHdrCodeRow: if definitionNode.header(role="http://www.eurofiling.info/role/2010/coordinate-code"): view.colHdrCodeRow = True ''' hdrNonStdRoles = view.colHdrNonStdRoles elif axisDisposition == "y": if ordDepth: #if not definitionNode.isAbstract: # view.dataRows += ordCardinality if nestedDepth - 1 > view.rowHdrCols: view.rowHdrCols = nestedDepth - 1 for j in range(1 + ordDepth): view.rowHdrColWidth.append(16) # min width for 'tail' of nonAbstract coordinate view.rowNonAbstractHdrSpanMin.append(0) checkLabelWidth(structuralNode, checkBoundFact=False) ''' if not view.rowHdrDocCol: if definitionNode.header(role="http://www.xbrl.org/2008/role/documentation", lang=view.lang): view.rowHdrDocCol = True if not view.rowHdrCodeCol: if definitionNode.header(role="http://www.eurofiling.info/role/2010/coordinate-code"): view.rowHdrCodeCol = True ''' hdrNonStdRoles = view.rowHdrNonStdRoles if axisDisposition in ("x", "y"): hdrNonStdPosition = -1 # where a match last occured for rel in view.modelXbrl.relationshipSet(XbrlConst.elementLabel).fromModelObject(definitionNode): if rel.toModelObject is not None and rel.toModelObject.role != XbrlConst.genStandardLabel: labelLang = rel.toModelObject.xmlLang labelRole = rel.toModelObject.role if (labelLang == view.lang or labelLang.startswith(view.lang) or view.lang.startswith(labelLang) or ("code" in labelRole)): labelRole = rel.toModelObject.role if labelRole in hdrNonStdRoles: hdrNonStdPosition = hdrNonStdRoles.index(labelRole) else: hdrNonStdRoles.insert(hdrNonStdPosition + 1, labelRole) isCartesianProductExpanded = False if not isinstance(definitionNode, ModelFilterDefinitionNode): # note: reduced set of facts should always be passed to subsequent open nodes isCartesianProductExpanded = True for axisSubtreeRel in subtreeRelationships: isCartesianProductExpanded = True childDefinitionNode = axisSubtreeRel.toModelObject if childDefinitionNode.isRollUp: structuralNode.rollUpStructuralNode = StructuralNode(structuralNode, breakdownNode, childDefinitionNode, ) if not structuralNode.childStructuralNodes: # first sub ordinate is the roll up structuralNode.subtreeRollUp = CHILD_ROLLUP_FIRST else: structuralNode.subtreeRollUp = CHILD_ROLLUP_LAST if not view.topRollup.get(axisDisposition): view.topRollup[axisDisposition] = structuralNode.subtreeRollUp else: if (isinstance(definitionNode, (ModelBreakdown, ModelCompositionDefinitionNode)) and isinstance(childDefinitionNode, ModelRelationshipDefinitionNode)): # append list products to composititionAxes subObjCntxs childStructuralNode = structuralNode else: childStructuralNode = StructuralNode(structuralNode, breakdownNode, childDefinitionNode) # others are nested structuralNode if axisDisposition != "z": structuralNode.childStructuralNodes.append(childStructuralNode) if axisDisposition != "z": expandDefinition(view, childStructuralNode, breakdownNode, childDefinitionNode, depth+ordDepth, axisDisposition, facts, i, tblAxisRels) #recurse cartesianProductExpander(childStructuralNode, *cartesianProductNestedArgs) else: childStructuralNode.indent = depth - 1 if structuralNode.choiceStructuralNodes is not None: structuralNode.choiceStructuralNodes.append(childStructuralNode) expandDefinition(view, childStructuralNode, breakdownNode, childDefinitionNode, depth + 1, axisDisposition, facts) #recurse # required when switching from abstract to roll up to determine abstractness #if not structuralNode.subtreeRollUp and structuralNode.childStructuralNodes and definitionNode.tag.endswith("Node"): # structuralNode.subtreeRollUp = CHILDREN_BUT_NO_ROLLUP #if not hasattr(structuralNode, "indent"): # probably also for multiple open axes if processOpenDefinitionNode: if isinstance(definitionNode, ModelRelationshipDefinitionNode): structuralNode.isLabeled = False selfStructuralNodes = {} if definitionNode.axis.endswith('-or-self') else None for rel in definitionNode.relationships(structuralNode): if not isinstance(rel, list): relChildStructuralNode = addRelationship(breakdownNode, definitionNode, rel, structuralNode, cartesianProductNestedArgs, selfStructuralNodes) else: addRelationships(breakdownNode, definitionNode, rel, relChildStructuralNode, cartesianProductNestedArgs) if axisDisposition == "z": # if definitionNode is first structural node child remove it if structuralNode.choiceStructuralNodes and structuralNode.choiceStructuralNodes[0].definitionNode == definitionNode: del structuralNode.choiceStructuralNodes[0] # flatten hierarchy of nested structural nodes inot choice nodes (for single listbox) def flattenChildNodesToChoices(childStructuralNodes, indent): while childStructuralNodes: choiceStructuralNode = childStructuralNodes.pop(0) choiceStructuralNode.indent = indent structuralNode.choiceStructuralNodes.append(choiceStructuralNode) flattenChildNodesToChoices(choiceStructuralNode.childStructuralNodes, indent + 1) flattenChildNodesToChoices(structuralNode.childStructuralNodes, 0) # set up by definitionNode.relationships if isinstance(definitionNode, ModelConceptRelationshipDefinitionNode): if (definitionNode._sourceQname != XbrlConst.qnXfiRoot and definitionNode._sourceQname not in view.modelXbrl.qnameConcepts): view.modelXbrl.error("xbrlte:invalidConceptRelationshipSource", _("Concept relationship rule node %(xlinkLabel)s source %(source)s does not refer to an existing concept."), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, source=definitionNode._sourceQname) elif isinstance(definitionNode, ModelDimensionRelationshipDefinitionNode): dim = view.modelXbrl.qnameConcepts.get(definitionNode._dimensionQname) if dim is None or not dim.isExplicitDimension: view.modelXbrl.error("xbrlte:invalidExplicitDimensionQName", _("Dimension relationship rule node %(xlinkLabel)s dimension %(dimension)s does not refer to an existing explicit dimension."), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, dimension=definitionNode._dimensionQname) domMbr = view.modelXbrl.qnameConcepts.get(definitionNode._sourceQname) if domMbr is None or not domMbr.isDomainMember: view.modelXbrl.error("xbrlte:invalidDimensionRelationshipSource", _("Dimension relationship rule node %(xlinkLabel)s source %(source)s does not refer to an existing domain member."), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, source=definitionNode._sourceQname) if (definitionNode._axis in ("child", "child-or-self", "parent", "parent-or-self", "sibling", "sibling-or-self") and (not isinstance(definitionNode._generations, _NUM_TYPES) or definitionNode._generations > 1)): view.modelXbrl.error("xbrlte:relationshipNodeTooManyGenerations ", _("Relationship rule node %(xlinkLabel)s formulaAxis %(axis)s implies a single generation tree walk but generations %(generations)s is greater than one."), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, axis=definitionNode._axis, generations=definitionNode._generations) elif isinstance(definitionNode, ModelSelectionDefinitionNode): structuralNode.setHasOpenNode() structuralNode.isLabeled = False isCartesianProductExpanded = True varQn = definitionNode.variableQname if varQn: selections = sorted(structuralNode.evaluate(definitionNode, definitionNode.evaluate) or [], key=lambda obj:sortkey(obj)) if isinstance(selections, (list,set,tuple)) and len(selections) > 1: for selection in selections: # nested choices from selection list childStructuralNode = StructuralNode(structuralNode, breakdownNode, definitionNode, contextItemFact=selection) childStructuralNode.variables[varQn] = selection childStructuralNode.indent = 0 if axisDisposition == "z": structuralNode.choiceStructuralNodes.append(childStructuralNode) childStructuralNode.zSelection = True else: structuralNode.childStructuralNodes.append(childStructuralNode) expandDefinition(view, childStructuralNode, breakdownNode, definitionNode, depth, axisDisposition, facts, processOpenDefinitionNode=False) #recurse cartesianProductExpander(childStructuralNode, *cartesianProductNestedArgs) else: structuralNode.variables[varQn] = selections elif isinstance(definitionNode, ModelFilterDefinitionNode): structuralNode.setHasOpenNode() structuralNode.isLabeled = False isCartesianProductExpanded = True structuralNode.abstract = True # spanning ordinate acts as a subtitle filteredFactsPartitions = structuralNode.evaluate(definitionNode, definitionNode.filteredFactsPartitions, evalArgs=(facts,)) if structuralNode._rendrCntx.formulaOptions.traceVariableFilterWinnowing: view.modelXbrl.info("table:trace", _("Filter node %(xlinkLabel)s facts partitions: %(factsPartitions)s"), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, factsPartitions=str(filteredFactsPartitions)) # ohly for fact entry (true if no parent open nodes or all are on entry prototype row) if axisDisposition != "z": childList = structuralNode.childStructuralNodes if structuralNode.isEntryPrototype(default=True): for i in range(getattr(view, "openBreakdownLines", # for file output, 1 entry row if no facts 0 if filteredFactsPartitions else 1)): view.aspectEntryObjectId += 1 filteredFactsPartitions.append([FactPrototype(view, {"aspectEntryObjectId": OPEN_ASPECT_ENTRY_SURROGATE + str(view.aspectEntryObjectId)})]) if structuralNode.isEntryPrototype(default=False): break # only one node per cartesian product under outermost nested open entry row else: childList = structuralNode.choiceStructuralNodes for factsPartition in filteredFactsPartitions: childStructuralNode = StructuralNode(structuralNode, breakdownNode, definitionNode, contextItemFact=factsPartition[0]) childStructuralNode.indent = 0 childStructuralNode.depth -= 1 # for label width; parent is merged/invisible childList.append(childStructuralNode) checkLabelWidth(childStructuralNode, checkBoundFact=True) #expandDefinition(view, childStructuralNode, breakdownNode, definitionNode, depth, axisDisposition, factsPartition, processOpenDefinitionNode=False) #recurse cartesianProductNestedArgs[3] = factsPartition # note: reduced set of facts should always be passed to subsequent open nodes if subtreeRelationships: for axisSubtreeRel in subtreeRelationships: child2DefinitionNode = axisSubtreeRel.toModelObject child2StructuralNode = StructuralNode(childStructuralNode, breakdownNode, child2DefinitionNode) # others are nested structuralNode childStructuralNode.childStructuralNodes.append(child2StructuralNode) expandDefinition(view, child2StructuralNode, breakdownNode, child2DefinitionNode, depth+ordDepth, axisDisposition, factsPartition) #recurse cartesianProductExpander(child2StructuralNode, *cartesianProductNestedArgs) else: cartesianProductExpander(childStructuralNode, *cartesianProductNestedArgs) # sort by header (which is likely to be typed dim value, for example) childList.sort(key=lambda childStructuralNode: childStructuralNode.header(lang=view.lang, returnGenLabel=False, returnMsgFormatString=False) or '') # exception on trying to sort if header returns None # TBD if there is no abstract 'sub header' for these subOrdCntxs, move them in place of parent structuralNode elif isinstance(definitionNode, ModelTupleDefinitionNode): structuralNode.abstract = True # spanning ordinate acts as a subtitle matchingTupleFacts = structuralNode.evaluate(definitionNode, definitionNode.filteredFacts, evalArgs=(facts,)) for tupleFact in matchingTupleFacts: childStructuralNode = StructuralNode(structuralNode, breakdownNode, definitionNode, contextItemFact=tupleFact) childStructuralNode.indent = 0 structuralNode.childStructuralNodes.append(childStructuralNode) expandDefinition(view, childStructuralNode, breakdownNode, definitionNode, depth, axisDisposition, [tupleFact]) #recurse # sort by header (which is likely to be typed dim value, for example) if any(sOC.header(lang=view.lang) for sOC in structuralNode.childStructuralNodes): structuralNode.childStructuralNodes.sort(key=lambda childStructuralNode: childStructuralNode.header(lang=view.lang) or '') elif isinstance(definitionNode, ModelRuleDefinitionNode): for constraintSet in definitionNode.constraintSets.values(): for aspect in constraintSet.aspectsCovered(): if not constraintSet.aspectValueDependsOnVars(aspect): if aspect == Aspect.CONCEPT: conceptQname = definitionNode.aspectValue(view.modelXbrl.rendrCntx, Aspect.CONCEPT) concept = view.modelXbrl.qnameConcepts.get(conceptQname) if concept is None or not concept.isItem or concept.isDimensionItem or concept.isHypercubeItem: view.modelXbrl.error("xbrlte:invalidQNameAspectValue", _("Rule node %(xlinkLabel)s specifies concept %(concept)s does not refer to an existing primary item concept."), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, concept=conceptQname) elif isinstance(aspect, QName): dim = view.modelXbrl.qnameConcepts.get(aspect) memQname = definitionNode.aspectValue(view.modelXbrl.rendrCntx, aspect) mem = view.modelXbrl.qnameConcepts.get(memQname) if dim is None or not dim.isDimensionItem: view.modelXbrl.error("xbrlte:invalidQNameAspectValue", _("Rule node %(xlinkLabel)s specifies dimension %(concept)s does not refer to an existing dimension concept."), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, concept=aspect) if isinstance(memQname, QName) and (mem is None or not mem.isDomainMember): view.modelXbrl.error("xbrlte:invalidQNameAspectValue", _("Rule node %(xlinkLabel)s specifies domain member %(concept)s does not refer to an existing domain member concept."), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, concept=memQname) if axisDisposition == "z": if structuralNode.choiceStructuralNodes: choiceNodeIndex = view.zOrdinateChoices.get(definitionNode, 0) if isinstance(choiceNodeIndex, dict): # aspect entry for open node structuralNode.aspects = choiceNodeIndex structuralNode.choiceNodeIndex = -1 elif choiceNodeIndex < len(structuralNode.choiceStructuralNodes): structuralNode.choiceNodeIndex = choiceNodeIndex else: structuralNode.choiceNodeIndex = 0 view.zmostOrdCntx = structuralNode if not isCartesianProductExpanded or (axisDisposition == "z" and structuralNode.choiceStructuralNodes is not None): cartesianProductExpander(structuralNode, *cartesianProductNestedArgs) if not structuralNode.childStructuralNodes: # childless root ordinate, make a child to iterate in producing table subOrdContext = StructuralNode(structuralNode, breakdownNode, definitionNode) except ResolutionException as ex: if sys.version[0] >= '3': #import traceback #traceback.print_tb(ex.__traceback__) raise ex.with_traceback(ex.__traceback__) # provide original traceback information else: raise ex except Exception as ex: e = ResolutionException("arelle:resolutionException", _("Exception in resolution of definition node %(node)s: %(error)s"), modelObject=definitionNode, node=definitionNode.qname, error=str(ex) ) if sys.version[0] >= '3': raise e.with_traceback(ex.__traceback__) # provide original traceback information else: raise e
def analyzeHdrs(view, structuralNode, definitionNode, depth, axisDisposition, facts, i=None, tblAxisRels=None, processOpenDefinitionNode=True): subtreeRelationships = view.axisSubtreeRelSet.fromModelObject(definitionNode) def checkLabelWidth(structuralNode, checkBoundFact=False): if axisDisposition == "y": # messages can't be evaluated, just use the text portion of format string label = structuralNode.header(lang=view.lang, returnGenLabel=not checkBoundFact, returnMsgFormatString=not checkBoundFact) if label: # need to et more exact word length in screen units widestWordLen = max(len(w) * 16 for w in label.split()) # abstract only pertains to subtree of closed nodesbut not cartesian products or open nodes if definitionNode.isAbstract or not subtreeRelationships: # isinstance(definitionNode, ModelOpenDefinitionNode): if widestWordLen > view.rowHdrColWidth[structuralNode.depth]: view.rowHdrColWidth[structuralNode.depth] = widestWordLen else: if widestWordLen > view.rowNonAbstractHdrSpanMin[structuralNode.depth]: view.rowNonAbstractHdrSpanMin[structuralNode.depth] = widestWordLen if structuralNode and isinstance(definitionNode, (ModelEuAxisCoord, ModelDefinitionNode)): try: #cartesianProductNestedArgs = (view, depth, axisDisposition, facts, tblAxisRels, i) ordCardinality, ordDepth = definitionNode.cardinalityAndDepth(structuralNode) nestedDepth = depth + ordDepth # HF test cartesianProductNestedArgs = [view, nestedDepth, axisDisposition, facts, tblAxisRels, i] if axisDisposition == "z": if depth == 1: # choices (combo boxes) don't add to z row count view.zAxisRows += 1 elif axisDisposition == "x": if ordDepth: if nestedDepth > view.colHdrRows: view.colHdrRows = nestedDepth ''' if not view.colHdrDocRow: if definitionNode.header(role="http://www.xbrl.org/2008/role/documentation", lang=view.lang): view.colHdrDocRow = True if not view.colHdrCodeRow: if definitionNode.header(role="http://www.eurofiling.info/role/2010/coordinate-code"): view.colHdrCodeRow = True ''' hdrNonStdRoles = view.colHdrNonStdRoles elif axisDisposition == "y": if ordDepth: #if not definitionNode.isAbstract: # view.dataRows += ordCardinality if nestedDepth > view.rowHdrCols: view.rowHdrCols = nestedDepth for j in range(1 + ordDepth): view.rowHdrColWidth.append(16) # min width for 'tail' of nonAbstract coordinate view.rowNonAbstractHdrSpanMin.append(0) checkLabelWidth(structuralNode, checkBoundFact=False) ''' if not view.rowHdrDocCol: if definitionNode.header(role="http://www.xbrl.org/2008/role/documentation", lang=view.lang): view.rowHdrDocCol = True if not view.rowHdrCodeCol: if definitionNode.header(role="http://www.eurofiling.info/role/2010/coordinate-code"): view.rowHdrCodeCol = True ''' hdrNonStdRoles = view.rowHdrNonStdRoles if axisDisposition in ("x", "y"): hdrNonStdPosition = -1 # where a match last occured for rel in view.modelXbrl.relationshipSet(XbrlConst.elementLabel).fromModelObject(definitionNode): if rel.toModelObject is not None and rel.toModelObject.role != XbrlConst.genStandardLabel: labelLang = rel.toModelObject.xmlLang labelRole = rel.toModelObject.role if (labelLang == view.lang or labelLang.startswith(view.lang) or view.lang.startswith(labelLang) or ("code" in labelRole)): labelRole = rel.toModelObject.role if labelRole in hdrNonStdRoles: hdrNonStdPosition = hdrNonStdRoles.index(labelRole) else: hdrNonStdRoles.insert(hdrNonStdPosition + 1, labelRole) cartesianProductAnalyzed = False for axisSubtreeRel in subtreeRelationships: cartesianProductAnalyzed = True childDefinitionNode = axisSubtreeRel.toModelObject if childDefinitionNode.isRollUp: structuralNode.rollUpStructuralNode = StructuralNode(structuralNode, childDefinitionNode) if not structuralNode.childStructuralNodes: # first sub ordinate is the roll up structuralNode.subtreeRollUp = CHILD_ROLLUP_FIRST else: structuralNode.subtreeRollUp = CHILD_ROLLUP_LAST if not view.topRollup.get(axisDisposition): view.topRollup[axisDisposition] = structuralNode.subtreeRollUp else: if (isinstance(definitionNode, ModelCompositionDefinitionNode) and isinstance(childDefinitionNode, ModelRelationshipDefinitionNode)): # append list products to composititionAxes subObjCntxs childStructuralNode = structuralNode else: childStructuralNode = StructuralNode(structuralNode, childDefinitionNode) # others are nested structuralNode if axisDisposition != "z": structuralNode.childStructuralNodes.append(childStructuralNode) if axisDisposition != "z": analyzeHdrs(view, childStructuralNode, childDefinitionNode, depth+ordDepth, axisDisposition, facts) #recurse analyzeCartesianProductHdrs(childStructuralNode, *cartesianProductNestedArgs) else: childStructuralNode.indent = depth - 1 structuralNode.choiceStructuralNodes.append(childStructuralNode) analyzeHdrs(view, structuralNode, childDefinitionNode, depth + 1, axisDisposition, facts) #recurse # required when switching from abstract to roll up to determine abstractness #if not structuralNode.subtreeRollUp and structuralNode.childStructuralNodes and definitionNode.tag.endswith("Node"): # structuralNode.subtreeRollUp = CHILDREN_BUT_NO_ROLLUP #if not hasattr(structuralNode, "indent"): # probably also for multiple open axes if processOpenDefinitionNode: if isinstance(definitionNode, ModelRelationshipDefinitionNode): selfStructuralNodes = {} if definitionNode.axis.endswith('-or-self') else None for rel in definitionNode.relationships(structuralNode): if not isinstance(rel, list): relChildStructuralNode = addRelationship(definitionNode, rel, structuralNode, cartesianProductNestedArgs, selfStructuralNodes) else: addRelationships(definitionNode, rel, relChildStructuralNode, cartesianProductNestedArgs) if axisDisposition == "z": # if definitionNode is first structural node child remove it if structuralNode.choiceStructuralNodes and structuralNode.choiceStructuralNodes[0].definitionNode == definitionNode: del structuralNode.choiceStructuralNodes[0] # flatten hierarchy of nested structural nodes inot choice nodes (for single listbox) def flattenChildNodesToChoices(childStructuralNodes, indent): while childStructuralNodes: choiceStructuralNode = childStructuralNodes.pop(0) choiceStructuralNode.indent = indent structuralNode.choiceStructuralNodes.append(choiceStructuralNode) flattenChildNodesToChoices(choiceStructuralNode.childStructuralNodes, indent + 1) flattenChildNodesToChoices(structuralNode.childStructuralNodes, 0) elif isinstance(definitionNode, ModelSelectionDefinitionNode): cartesianProductAnalyzed = True varQn = definitionNode.variableQname if varQn: selections = sorted(structuralNode.evaluate(definitionNode, definitionNode.evaluate) or [], key=lambda obj:sortkey(obj)) if isinstance(selections, (list,set,tuple)) and len(selections) > 1: for selection in selections: # nested choices from selection list childStructuralNode = StructuralNode(structuralNode, definitionNode, contextItemFact=selection) childStructuralNode.variables[varQn] = selection childStructuralNode.indent = 0 if axisDisposition == "z": structuralNode.choiceStructuralNodes.append(childStructuralNode) childStructuralNode.zSelection = True else: structuralNode.childStructuralNodes.append(childStructuralNode) analyzeHdrs(view, childStructuralNode, definitionNode, depth, axisDisposition, facts, processOpenDefinitionNode=False) #recurse analyzeCartesianProductHdrs(childStructuralNode, *cartesianProductNestedArgs) else: structuralNode.variables[varQn] = selections elif isinstance(definitionNode, ModelFilterDefinitionNode): cartesianProductAnalyzed = True structuralNode.abstract = True # spanning ordinate acts as a subtitle filteredFactsPartitions = structuralNode.evaluate(definitionNode, definitionNode.filteredFactsPartitions, evalArgs=(facts,)) for factsPartition in filteredFactsPartitions: childStructuralNode = StructuralNode(structuralNode, definitionNode, contextItemFact=factsPartition[0]) childStructuralNode.indent = 0 structuralNode.childStructuralNodes.append(childStructuralNode) checkLabelWidth(childStructuralNode, checkBoundFact=True) #analyzeHdrs(view, childStructuralNode, definitionNode, depth, axisDisposition, factsPartition, processOpenDefinitionNode=False) #recurse cartesianProductNestedArgs[3] = factsPartition analyzeCartesianProductHdrs(childStructuralNode, *cartesianProductNestedArgs) # sort by header (which is likely to be typed dim value, for example) structuralNode.childStructuralNodes.sort(key=lambda childStructuralNode: childStructuralNode.header(lang=view.lang, returnGenLabel=False, returnMsgFormatString=False) or '') # exception on trying to sort if header returns None # TBD if there is no abstract 'sub header' for these subOrdCntxs, move them in place of parent structuralNode elif isinstance(definitionNode, ModelTupleDefinitionNode): structuralNode.abstract = True # spanning ordinate acts as a subtitle matchingTupleFacts = structuralNode.evaluate(definitionNode, definitionNode.filteredFacts, evalArgs=(facts,)) for tupleFact in matchingTupleFacts: childStructuralNode = StructuralNode(structuralNode, definitionNode, contextItemFact=tupleFact) childStructuralNode.indent = 0 structuralNode.childStructuralNodes.append(childStructuralNode) analyzeHdrs(view, childStructuralNode, definitionNode, depth, axisDisposition, [tupleFact]) #recurse # sort by header (which is likely to be typed dim value, for example) if any(sOC.header(lang=view.lang) for sOC in structuralNode.childStructuralNodes): structuralNode.childStructuralNodes.sort(key=lambda childStructuralNode: childStructuralNode.header(lang=view.lang) or '') if axisDisposition == "z": if structuralNode.choiceStructuralNodes: choiceNodeIndex = view.zOrdinateChoices.get(definitionNode, 0) if choiceNodeIndex < len(structuralNode.choiceStructuralNodes): structuralNode.choiceNodeIndex = choiceNodeIndex else: structuralNode.choiceNodeIndex = 0 view.zmostOrdCntx = structuralNode if not cartesianProductAnalyzed or axisDisposition == "z": analyzeCartesianProductHdrs(structuralNode, *cartesianProductNestedArgs) if not structuralNode.childStructuralNodes: # childless root ordinate, make a child to iterate in producing table subOrdContext = StructuralNode(structuralNode, definitionNode) except ResolutionException as ex: raise ex except Exception as ex: raise ResolutionException("arelle:resolutionException", _("Exception in resolution of definition node %(node)s: %(error)s"), modelObject=definitionNode, node=definitionNode.qname, error=str(ex) ).with_traceback(ex.__traceback__) # provide original traceback information
def analyzeHdrs(view, structuralNode, definitionNode, depth, axisDisposition, facts, i=None, tblAxisRels=None, processOpenDefinitionNode=True): subtreeRelationships = view.axisSubtreeRelSet.fromModelObject(definitionNode) def checkLabelWidth(structuralNode, checkBoundFact=False): if axisDisposition == "y": # messages can't be evaluated, just use the text portion of format string label = structuralNode.header(lang=view.lang, returnGenLabel=not checkBoundFact, returnMsgFormatString=not checkBoundFact) if label: # need to et more exact word length in screen units widestWordLen = max(len(w) * 16 for w in label.split()) # abstract only pertains to subtree of closed nodesbut not cartesian products or open nodes if definitionNode.isAbstract or not subtreeRelationships: # isinstance(definitionNode, ModelOpenDefinitionNode): if widestWordLen > view.rowHdrColWidth[structuralNode.depth]: view.rowHdrColWidth[structuralNode.depth] = widestWordLen else: if widestWordLen > view.rowNonAbstractHdrSpanMin[structuralNode.depth]: view.rowNonAbstractHdrSpanMin[structuralNode.depth] = widestWordLen if structuralNode and isinstance(definitionNode, (ModelBreakdown, ModelEuAxisCoord, ModelDefinitionNode)): try: #cartesianProductNestedArgs = (view, depth, axisDisposition, facts, tblAxisRels, i) ordCardinality, ordDepth = definitionNode.cardinalityAndDepth(structuralNode) nestedDepth = depth + ordDepth # HF test cartesianProductNestedArgs = [view, nestedDepth, axisDisposition, facts, tblAxisRels, i] if axisDisposition == "z": if depth == 1: # choices (combo boxes) don't add to z row count view.zAxisRows += 1 elif axisDisposition == "x": if ordDepth: if nestedDepth > view.colHdrRows: view.colHdrRows = nestedDepth ''' if not view.colHdrDocRow: if definitionNode.header(role="http://www.xbrl.org/2008/role/documentation", lang=view.lang): view.colHdrDocRow = True if not view.colHdrCodeRow: if definitionNode.header(role="http://www.eurofiling.info/role/2010/coordinate-code"): view.colHdrCodeRow = True ''' hdrNonStdRoles = view.colHdrNonStdRoles elif axisDisposition == "y": if ordDepth: #if not definitionNode.isAbstract: # view.dataRows += ordCardinality if nestedDepth > view.rowHdrCols: view.rowHdrCols = nestedDepth for j in range(1 + ordDepth): view.rowHdrColWidth.append(16) # min width for 'tail' of nonAbstract coordinate view.rowNonAbstractHdrSpanMin.append(0) checkLabelWidth(structuralNode, checkBoundFact=False) ''' if not view.rowHdrDocCol: if definitionNode.header(role="http://www.xbrl.org/2008/role/documentation", lang=view.lang): view.rowHdrDocCol = True if not view.rowHdrCodeCol: if definitionNode.header(role="http://www.eurofiling.info/role/2010/coordinate-code"): view.rowHdrCodeCol = True ''' hdrNonStdRoles = view.rowHdrNonStdRoles if axisDisposition in ("x", "y"): hdrNonStdPosition = -1 # where a match last occured for rel in view.modelXbrl.relationshipSet(XbrlConst.elementLabel).fromModelObject(definitionNode): if rel.toModelObject is not None and rel.toModelObject.role != XbrlConst.genStandardLabel: labelLang = rel.toModelObject.xmlLang labelRole = rel.toModelObject.role if (labelLang == view.lang or labelLang.startswith(view.lang) or view.lang.startswith(labelLang) or ("code" in labelRole)): labelRole = rel.toModelObject.role if labelRole in hdrNonStdRoles: hdrNonStdPosition = hdrNonStdRoles.index(labelRole) else: hdrNonStdRoles.insert(hdrNonStdPosition + 1, labelRole) cartesianProductAnalyzed = False for axisSubtreeRel in subtreeRelationships: cartesianProductAnalyzed = True childDefinitionNode = axisSubtreeRel.toModelObject if childDefinitionNode.isRollUp: structuralNode.rollUpStructuralNode = StructuralNode(structuralNode, childDefinitionNode) if not structuralNode.childStructuralNodes: # first sub ordinate is the roll up structuralNode.subtreeRollUp = CHILD_ROLLUP_FIRST else: structuralNode.subtreeRollUp = CHILD_ROLLUP_LAST if not view.topRollup.get(axisDisposition): view.topRollup[axisDisposition] = structuralNode.subtreeRollUp else: if (isinstance(definitionNode, (ModelBreakdown, ModelCompositionDefinitionNode)) and isinstance(childDefinitionNode, ModelRelationshipDefinitionNode)): # append list products to composititionAxes subObjCntxs childStructuralNode = structuralNode else: childStructuralNode = StructuralNode(structuralNode, childDefinitionNode) # others are nested structuralNode if axisDisposition != "z": structuralNode.childStructuralNodes.append(childStructuralNode) if axisDisposition != "z": analyzeHdrs(view, childStructuralNode, childDefinitionNode, depth+ordDepth, axisDisposition, facts) #recurse analyzeCartesianProductHdrs(childStructuralNode, *cartesianProductNestedArgs) else: childStructuralNode.indent = depth - 1 structuralNode.choiceStructuralNodes.append(childStructuralNode) analyzeHdrs(view, structuralNode, childDefinitionNode, depth + 1, axisDisposition, facts) #recurse # required when switching from abstract to roll up to determine abstractness #if not structuralNode.subtreeRollUp and structuralNode.childStructuralNodes and definitionNode.tag.endswith("Node"): # structuralNode.subtreeRollUp = CHILDREN_BUT_NO_ROLLUP #if not hasattr(structuralNode, "indent"): # probably also for multiple open axes if processOpenDefinitionNode: if isinstance(definitionNode, ModelRelationshipDefinitionNode): selfStructuralNodes = {} if definitionNode.axis.endswith('-or-self') else None for rel in definitionNode.relationships(structuralNode): if not isinstance(rel, list): relChildStructuralNode = addRelationship(definitionNode, rel, structuralNode, cartesianProductNestedArgs, selfStructuralNodes) else: addRelationships(definitionNode, rel, relChildStructuralNode, cartesianProductNestedArgs) if axisDisposition == "z": # if definitionNode is first structural node child remove it if structuralNode.choiceStructuralNodes and structuralNode.choiceStructuralNodes[0].definitionNode == definitionNode: del structuralNode.choiceStructuralNodes[0] # flatten hierarchy of nested structural nodes inot choice nodes (for single listbox) def flattenChildNodesToChoices(childStructuralNodes, indent): while childStructuralNodes: choiceStructuralNode = childStructuralNodes.pop(0) choiceStructuralNode.indent = indent structuralNode.choiceStructuralNodes.append(choiceStructuralNode) flattenChildNodesToChoices(choiceStructuralNode.childStructuralNodes, indent + 1) flattenChildNodesToChoices(structuralNode.childStructuralNodes, 0) elif isinstance(definitionNode, ModelSelectionDefinitionNode): cartesianProductAnalyzed = True varQn = definitionNode.variableQname if varQn: selections = sorted(structuralNode.evaluate(definitionNode, definitionNode.evaluate) or [], key=lambda obj:sortkey(obj)) if isinstance(selections, (list,set,tuple)) and len(selections) > 1: for selection in selections: # nested choices from selection list childStructuralNode = StructuralNode(structuralNode, definitionNode, contextItemFact=selection) childStructuralNode.variables[varQn] = selection childStructuralNode.indent = 0 if axisDisposition == "z": structuralNode.choiceStructuralNodes.append(childStructuralNode) childStructuralNode.zSelection = True else: structuralNode.childStructuralNodes.append(childStructuralNode) analyzeHdrs(view, childStructuralNode, definitionNode, depth, axisDisposition, facts, processOpenDefinitionNode=False) #recurse analyzeCartesianProductHdrs(childStructuralNode, *cartesianProductNestedArgs) else: structuralNode.variables[varQn] = selections elif isinstance(definitionNode, ModelFilterDefinitionNode): cartesianProductAnalyzed = True structuralNode.abstract = True # spanning ordinate acts as a subtitle filteredFactsPartitions = structuralNode.evaluate(definitionNode, definitionNode.filteredFactsPartitions, evalArgs=(facts,)) if structuralNode._rendrCntx.formulaOptions.traceVariableFilterWinnowing: view.modelXbrl.info("table:trace", _("Filter node %(xlinkLabel)s facts partitions: %(factsPartitions)s"), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, factsPartitions=str(filteredFactsPartitions)) for factsPartition in filteredFactsPartitions: childStructuralNode = StructuralNode(structuralNode, definitionNode, contextItemFact=factsPartition[0]) childStructuralNode.indent = 0 structuralNode.childStructuralNodes.append(childStructuralNode) checkLabelWidth(childStructuralNode, checkBoundFact=True) #analyzeHdrs(view, childStructuralNode, definitionNode, depth, axisDisposition, factsPartition, processOpenDefinitionNode=False) #recurse cartesianProductNestedArgs[3] = factsPartition analyzeCartesianProductHdrs(childStructuralNode, *cartesianProductNestedArgs) # sort by header (which is likely to be typed dim value, for example) structuralNode.childStructuralNodes.sort(key=lambda childStructuralNode: childStructuralNode.header(lang=view.lang, returnGenLabel=False, returnMsgFormatString=False) or '') # exception on trying to sort if header returns None # TBD if there is no abstract 'sub header' for these subOrdCntxs, move them in place of parent structuralNode elif isinstance(definitionNode, ModelTupleDefinitionNode): structuralNode.abstract = True # spanning ordinate acts as a subtitle matchingTupleFacts = structuralNode.evaluate(definitionNode, definitionNode.filteredFacts, evalArgs=(facts,)) for tupleFact in matchingTupleFacts: childStructuralNode = StructuralNode(structuralNode, definitionNode, contextItemFact=tupleFact) childStructuralNode.indent = 0 structuralNode.childStructuralNodes.append(childStructuralNode) analyzeHdrs(view, childStructuralNode, definitionNode, depth, axisDisposition, [tupleFact]) #recurse # sort by header (which is likely to be typed dim value, for example) if any(sOC.header(lang=view.lang) for sOC in structuralNode.childStructuralNodes): structuralNode.childStructuralNodes.sort(key=lambda childStructuralNode: childStructuralNode.header(lang=view.lang) or '') if axisDisposition == "z": if structuralNode.choiceStructuralNodes: choiceNodeIndex = view.zOrdinateChoices.get(definitionNode, 0) if choiceNodeIndex < len(structuralNode.choiceStructuralNodes): structuralNode.choiceNodeIndex = choiceNodeIndex else: structuralNode.choiceNodeIndex = 0 view.zmostOrdCntx = structuralNode if not cartesianProductAnalyzed or axisDisposition == "z": analyzeCartesianProductHdrs(structuralNode, *cartesianProductNestedArgs) if not structuralNode.childStructuralNodes: # childless root ordinate, make a child to iterate in producing table subOrdContext = StructuralNode(structuralNode, definitionNode) except ResolutionException as ex: raise ex except Exception as ex: e = ResolutionException("arelle:resolutionException", _("Exception in resolution of definition node %(node)s: %(error)s"), modelObject=definitionNode, node=definitionNode.qname, error=str(ex) ) if sys.version[0] >= '3': raise e.with_traceback(ex.__traceback__) # provide original traceback information else: raise e
def expandDefinition(view, structuralNode, breakdownNode, definitionNode, depth, axisDisposition, facts, i=None, tblAxisRels=None, processOpenDefinitionNode=True): subtreeRelationships = view.axisSubtreeRelSet.fromModelObject( definitionNode) def checkLabelWidth(structuralNode, checkBoundFact=False): if axisDisposition == "y": # messages can't be evaluated, just use the text portion of format string label = structuralNode.header( lang=view.lang, returnGenLabel=not checkBoundFact, returnMsgFormatString=not checkBoundFact) if label: # need to et more exact word length in screen units widestWordLen = max( len(w) * RENDER_UNITS_PER_CHAR for w in label.split()) # abstract only pertains to subtree of closed nodesbut not cartesian products or open nodes while structuralNode.depth >= len(view.rowHdrColWidth): view.rowHdrColWidth.append(0) if definitionNode.isAbstract or not subtreeRelationships: # isinstance(definitionNode, ModelOpenDefinitionNode): if widestWordLen > view.rowHdrColWidth[ structuralNode.depth]: view.rowHdrColWidth[ structuralNode.depth] = widestWordLen else: if widestWordLen > view.rowNonAbstractHdrSpanMin[ structuralNode.depth]: view.rowNonAbstractHdrSpanMin[ structuralNode.depth] = widestWordLen if structuralNode and isinstance( definitionNode, (ModelBreakdown, ModelEuAxisCoord, ModelDefinitionNode)): try: #cartesianProductNestedArgs = (view, depth, axisDisposition, facts, tblAxisRels, i) ordCardinality, ordDepth = definitionNode.cardinalityAndDepth( structuralNode) if (not definitionNode.isAbstract and isinstance(definitionNode, ModelClosedDefinitionNode) and ordCardinality == 0): view.modelXbrl.error( "xbrlte:closedDefinitionNodeZeroCardinality", _("Closed definition node %(xlinkLabel)s does not contribute at least one structural node" ), modelObject=(view.modelTable, definitionNode), xlinkLabel=definitionNode.xlinkLabel, axis=definitionNode.localName) nestedDepth = depth + ordDepth # HF test cartesianProductNestedArgs = [ view, nestedDepth, axisDisposition, facts, tblAxisRels, i ] if axisDisposition == "z": if depth == 1: # choices (combo boxes) don't add to z row count view.zAxisRows += 1 elif axisDisposition == "x": if ordDepth: if nestedDepth - 1 > view.colHdrRows: view.colHdrRows = nestedDepth - 1 ''' if not view.colHdrDocRow: if definitionNode.header(role="http://www.xbrl.org/2008/role/documentation", lang=view.lang): view.colHdrDocRow = True if not view.colHdrCodeRow: if definitionNode.header(role="http://www.eurofiling.info/role/2010/coordinate-code"): view.colHdrCodeRow = True ''' hdrNonStdRoles = view.colHdrNonStdRoles elif axisDisposition == "y": if ordDepth: #if not definitionNode.isAbstract: # view.dataRows += ordCardinality if nestedDepth - 1 > view.rowHdrCols: view.rowHdrCols = nestedDepth - 1 for j in range(1 + ordDepth): view.rowHdrColWidth.append( RENDER_UNITS_PER_CHAR ) # min width for 'tail' of nonAbstract coordinate view.rowNonAbstractHdrSpanMin.append(0) checkLabelWidth(structuralNode, checkBoundFact=False) ''' if not view.rowHdrDocCol: if definitionNode.header(role="http://www.xbrl.org/2008/role/documentation", lang=view.lang): view.rowHdrDocCol = True if not view.rowHdrCodeCol: if definitionNode.header(role="http://www.eurofiling.info/role/2010/coordinate-code"): view.rowHdrCodeCol = True ''' hdrNonStdRoles = view.rowHdrNonStdRoles if axisDisposition in ("x", "y"): hdrNonStdPosition = -1 # where a match last occured for rel in view.modelXbrl.relationshipSet( XbrlConst.elementLabel).fromModelObject( definitionNode): if rel.toModelObject is not None and rel.toModelObject.role != XbrlConst.genStandardLabel: labelLang = rel.toModelObject.xmlLang labelRole = rel.toModelObject.role if (labelLang == view.lang or labelLang.startswith(view.lang) or view.lang.startswith(labelLang) or ("code" in labelRole)): labelRole = rel.toModelObject.role if labelRole in hdrNonStdRoles: hdrNonStdPosition = hdrNonStdRoles.index( labelRole) else: hdrNonStdRoles.insert(hdrNonStdPosition + 1, labelRole) isCartesianProductExpanded = False if not isinstance(definitionNode, ModelFilterDefinitionNode): isCartesianProductExpanded = True # note: reduced set of facts should always be passed to subsequent open nodes for axisSubtreeRel in subtreeRelationships: childDefinitionNode = axisSubtreeRel.toModelObject if childDefinitionNode.isRollUp: structuralNode.rollUpStructuralNode = StructuralNode( structuralNode, breakdownNode, childDefinitionNode, ) if not structuralNode.childStructuralNodes: # first sub ordinate is the roll up structuralNode.subtreeRollUp = CHILD_ROLLUP_FIRST else: structuralNode.subtreeRollUp = CHILD_ROLLUP_LAST if not view.topRollup.get(axisDisposition): view.topRollup[ axisDisposition] = structuralNode.subtreeRollUp else: if ( isinstance(definitionNode, (ModelBreakdown, ModelCompositionDefinitionNode)) and isinstance( childDefinitionNode, ModelRelationshipDefinitionNode) ): # append list products to composititionAxes subObjCntxs childStructuralNode = structuralNode else: childStructuralNode = StructuralNode( structuralNode, breakdownNode, childDefinitionNode ) # others are nested structuralNode if axisDisposition != "z": structuralNode.childStructuralNodes.append( childStructuralNode) if axisDisposition != "z": expandDefinition(view, childStructuralNode, breakdownNode, childDefinitionNode, depth + ordDepth, axisDisposition, facts, i, tblAxisRels) #recurse cartesianProductExpander( childStructuralNode, *cartesianProductNestedArgs) else: childStructuralNode.indent = depth - 1 if structuralNode.choiceStructuralNodes is not None: structuralNode.choiceStructuralNodes.append( childStructuralNode) expandDefinition(view, childStructuralNode, breakdownNode, childDefinitionNode, depth + 1, axisDisposition, facts) #recurse # required when switching from abstract to roll up to determine abstractness #if not structuralNode.subtreeRollUp and structuralNode.childStructuralNodes and definitionNode.tag.endswith("Node"): # structuralNode.subtreeRollUp = CHILDREN_BUT_NO_ROLLUP #if not hasattr(structuralNode, "indent"): # probably also for multiple open axes if processOpenDefinitionNode: if isinstance(definitionNode, ModelRelationshipDefinitionNode): structuralNode.isLabeled = False selfStructuralNodes = {} if definitionNode.axis.endswith( '-or-self') else None for rel in definitionNode.relationships(structuralNode): if not isinstance(rel, list): relChildStructuralNode = addRelationship( breakdownNode, definitionNode, rel, structuralNode, cartesianProductNestedArgs, selfStructuralNodes) else: addRelationships(breakdownNode, definitionNode, rel, relChildStructuralNode, cartesianProductNestedArgs) if axisDisposition == "z": # if definitionNode is first structural node child remove it if structuralNode.choiceStructuralNodes and structuralNode.choiceStructuralNodes[ 0].definitionNode == definitionNode: del structuralNode.choiceStructuralNodes[0] # flatten hierarchy of nested structural nodes inot choice nodes (for single listbox) def flattenChildNodesToChoices(childStructuralNodes, indent): while childStructuralNodes: choiceStructuralNode = childStructuralNodes.pop( 0) choiceStructuralNode.indent = indent structuralNode.choiceStructuralNodes.append( choiceStructuralNode) flattenChildNodesToChoices( choiceStructuralNode.childStructuralNodes, indent + 1) if structuralNode.childStructuralNodes: flattenChildNodesToChoices( structuralNode.childStructuralNodes, 0) # set up by definitionNode.relationships if isinstance(definitionNode, ModelConceptRelationshipDefinitionNode): if (definitionNode._sourceQname != XbrlConst.qnXfiRoot and definitionNode._sourceQname not in view.modelXbrl.qnameConcepts): view.modelXbrl.error( "xbrlte:invalidConceptRelationshipSource", _("Concept relationship rule node %(xlinkLabel)s source %(source)s does not refer to an existing concept." ), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, source=definitionNode._sourceQname) elif isinstance(definitionNode, ModelDimensionRelationshipDefinitionNode): dim = view.modelXbrl.qnameConcepts.get( definitionNode._dimensionQname) if dim is None or not dim.isExplicitDimension: view.modelXbrl.error( "xbrlte:invalidExplicitDimensionQName", _("Dimension relationship rule node %(xlinkLabel)s dimension %(dimension)s does not refer to an existing explicit dimension." ), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, dimension=definitionNode._dimensionQname) domMbr = view.modelXbrl.qnameConcepts.get( definitionNode._sourceQname) if domMbr is None or not domMbr.isDomainMember: view.modelXbrl.error( "xbrlte:invalidDimensionRelationshipSource", _("Dimension relationship rule node %(xlinkLabel)s source %(source)s does not refer to an existing domain member." ), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, source=definitionNode._sourceQname) if (definitionNode._axis in ("child", "child-or-self", "parent", "parent-or-self", "sibling", "sibling-or-self") and (not isinstance(definitionNode._generations, _NUM_TYPES) or definitionNode._generations > 1)): view.modelXbrl.error( "xbrlte:relationshipNodeTooManyGenerations ", _("Relationship rule node %(xlinkLabel)s formulaAxis %(axis)s implies a single generation tree walk but generations %(generations)s is greater than one." ), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, axis=definitionNode._axis, generations=definitionNode._generations) elif isinstance(definitionNode, ModelSelectionDefinitionNode): structuralNode.setHasOpenNode() structuralNode.isLabeled = False isCartesianProductExpanded = True varQn = definitionNode.variableQname if varQn: selections = sorted(structuralNode.evaluate( definitionNode, definitionNode.evaluate) or [], key=lambda obj: sortkey(obj)) if isinstance( selections, (list, set, tuple)) and len(selections) > 1: for selection in selections: # nested choices from selection list childStructuralNode = StructuralNode( structuralNode, breakdownNode, definitionNode, contextItemFact=selection) childStructuralNode.variables[ varQn] = selection childStructuralNode.indent = 0 if axisDisposition == "z": structuralNode.choiceStructuralNodes.append( childStructuralNode) childStructuralNode.zSelection = True else: structuralNode.childStructuredNodeList.append( childStructuralNode) expandDefinition( view, childStructuralNode, breakdownNode, definitionNode, depth, axisDisposition, facts, processOpenDefinitionNode=False ) #recurse cartesianProductExpander( childStructuralNode, *cartesianProductNestedArgs) else: structuralNode.variables[varQn] = selections elif isinstance(definitionNode, ModelFilterDefinitionNode): structuralNode.setHasOpenNode() structuralNode.isLabeled = False isCartesianProductExpanded = True structuralNode.abstract = True # spanning ordinate acts as a subtitle filteredFactsPartitions = structuralNode.evaluate( definitionNode, definitionNode.filteredFactsPartitions, evalArgs=(facts, )) if structuralNode._rendrCntx.formulaOptions.traceVariableFilterWinnowing: view.modelXbrl.info( "table:trace", _("Filter node %(xlinkLabel)s facts partitions: %(factsPartitions)s" ), modelObject=definitionNode, xlinkLabel=definitionNode.xlinkLabel, factsPartitions=str(filteredFactsPartitions)) # ohly for fact entry (true if no parent open nodes or all are on entry prototype row) if axisDisposition != "z": childList = structuralNode.childStructuralNodes if structuralNode.isEntryPrototype(default=True): for i in range( getattr( view, "openBreakdownLines", # for file output, 1 entry row if no facts 0 if filteredFactsPartitions else 1)): view.aspectEntryObjectId += 1 filteredFactsPartitions.append([ FactPrototype( view, { "aspectEntryObjectId": OPEN_ASPECT_ENTRY_SURROGATE + str(view.aspectEntryObjectId) }) ]) if structuralNode.isEntryPrototype( default=False): break # only one node per cartesian product under outermost nested open entry row else: childList = structuralNode.choiceStructuralNodes for factsPartition in filteredFactsPartitions: childStructuralNode = StructuralNode( structuralNode, breakdownNode, definitionNode, contextItemFact=factsPartition[0]) childStructuralNode.indent = 0 childStructuralNode.depth -= 1 # for label width; parent is merged/invisible childList.append(childStructuralNode) checkLabelWidth(childStructuralNode, checkBoundFact=True) #expandDefinition(view, childStructuralNode, breakdownNode, definitionNode, depth, axisDisposition, factsPartition, processOpenDefinitionNode=False) #recurse cartesianProductNestedArgs[3] = factsPartition # note: reduced set of facts should always be passed to subsequent open nodes if subtreeRelationships: for axisSubtreeRel in subtreeRelationships: child2DefinitionNode = axisSubtreeRel.toModelObject child2StructuralNode = StructuralNode( childStructuralNode, breakdownNode, child2DefinitionNode ) # others are nested structuralNode childStructuralNode.childStructuredNodeList.append( child2StructuralNode) expandDefinition(view, child2StructuralNode, breakdownNode, child2DefinitionNode, depth + ordDepth, axisDisposition, factsPartition) #recurse cartesianProductExpander( child2StructuralNode, *cartesianProductNestedArgs) else: cartesianProductExpander( childStructuralNode, *cartesianProductNestedArgs) # sort by header (which is likely to be typed dim value, for example) childList.sort( key=lambda childStructuralNode: childStructuralNode. header(lang=view.lang, returnGenLabel=False, returnMsgFormatString=False) or '' ) # exception on trying to sort if header returns None # TBD if there is no abstract 'sub header' for these subOrdCntxs, move them in place of parent structuralNode elif isinstance(definitionNode, ModelTupleDefinitionNode): structuralNode.abstract = True # spanning ordinate acts as a subtitle matchingTupleFacts = structuralNode.evaluate( definitionNode, definitionNode.filteredFacts, evalArgs=(facts, )) for tupleFact in matchingTupleFacts: childStructuralNode = StructuralNode( structuralNode, breakdownNode, definitionNode, contextItemFact=tupleFact) childStructuralNode.indent = 0 structuralNode.childStructuredNodeList.append( childStructuralNode) expandDefinition(view, childStructuralNode, breakdownNode, definitionNode, depth, axisDisposition, [tupleFact]) #recurse # sort by header (which is likely to be typed dim value, for example) if (structuralNode.childStructuralNodes and any( sOC.header(lang=view.lang) for sOC in structuralNode.childStructuralNodes)): structuralNode.childStructuralNodes.sort( key=lambda childStructuralNode: childStructuralNode .header(lang=view.lang) or '') elif isinstance(definitionNode, ModelRuleDefinitionNode): for constraintSet in definitionNode.constraintSets.values( ): for aspect in constraintSet.aspectsCovered(): if not constraintSet.aspectValueDependsOnVars( aspect): if aspect == Aspect.CONCEPT: conceptQname = definitionNode.aspectValue( view.rendrCntx, Aspect.CONCEPT) concept = view.modelXbrl.qnameConcepts.get( conceptQname) if concept is None or not concept.isItem or concept.isDimensionItem or concept.isHypercubeItem: view.modelXbrl.error( "xbrlte:invalidQNameAspectValue", _("Rule node %(xlinkLabel)s specifies concept %(concept)s does not refer to an existing primary item concept." ), modelObject=definitionNode, xlinkLabel=definitionNode. xlinkLabel, concept=conceptQname) elif isinstance(aspect, QName): dim = view.modelXbrl.qnameConcepts.get( aspect) memQname = definitionNode.aspectValue( view.rendrCntx, aspect) mem = view.modelXbrl.qnameConcepts.get( memQname) if dim is None or not dim.isDimensionItem: view.modelXbrl.error( "xbrlte:invalidQNameAspectValue", _("Rule node %(xlinkLabel)s specifies dimension %(concept)s does not refer to an existing dimension concept." ), modelObject=definitionNode, xlinkLabel=definitionNode. xlinkLabel, concept=aspect) if isinstance(memQname, QName) and ( mem is None or not mem.isDomainMember): view.modelXbrl.error( "xbrlte:invalidQNameAspectValue", _("Rule node %(xlinkLabel)s specifies domain member %(concept)s does not refer to an existing domain member concept." ), modelObject=definitionNode, xlinkLabel=definitionNode. xlinkLabel, concept=memQname) if axisDisposition == "z": if structuralNode.choiceStructuralNodes: choiceNodeIndex = view.zOrdinateChoices.get( definitionNode, 0) if isinstance(choiceNodeIndex, dict): # aspect entry for open node structuralNode.aspects = choiceNodeIndex structuralNode.choiceNodeIndex = -1 elif choiceNodeIndex < len( structuralNode.choiceStructuralNodes): structuralNode.choiceNodeIndex = choiceNodeIndex else: structuralNode.choiceNodeIndex = 0 view.zmostOrdCntx = structuralNode if not isCartesianProductExpanded or ( axisDisposition == "z" and structuralNode.choiceStructuralNodes is not None): cartesianProductExpander(structuralNode, *cartesianProductNestedArgs) if not structuralNode.childStructuralNodes: # childless root ordinate, make a child to iterate in producing table subOrdContext = StructuralNode(structuralNode, breakdownNode, definitionNode) except ResolutionException as ex: if sys.version[0] >= '3': #import traceback #traceback.print_tb(ex.__traceback__) raise ex.with_traceback( ex.__traceback__) # provide original traceback information else: raise ex except Exception as ex: e = ResolutionException( "arelle:resolutionException", _("Exception in resolution of definition node %(node)s: %(error)s" ), modelObject=definitionNode, node=definitionNode.qname, error=str(ex)) if sys.version[0] >= '3': raise e.with_traceback( ex.__traceback__) # provide original traceback information else: raise e