示例#1
0
 def nonDimHash(self):
     try:
         return self._nonDimsHash
     except AttributeError:
         self._nonDimsHash = hash( (XbrlUtil.equalityHash(self.nonDimValues("segment")), 
                                    XbrlUtil.equalityHash(self.nonDimValues("scenario"))) )
         return self._nonDimsHash
示例#2
0
    def isEqualTo_(self, cntx2, dimensionalAspectModel):
        if cntx2 is None:
            return False
        if cntx2 == self:  # same context
            return True
        if (self.periodHash != cntx2.periodHash
                or self.entityIdentifierHash != cntx2.entityIdentifierHash):
            return False
        if dimensionalAspectModel:
            if (self.dimsHash != cntx2.dimsHash
                    or self.nonDimHash != cntx2.nonDimHash):
                return False
        else:
            if (self.segmentHash != cntx2.segmentHash
                    or self.scenarioHash != cntx2.scenarioHash):
                return False
        if self.periodHash != cntx2.periodHash or not self.isPeriodEqualTo(
                cntx2) or not self.isEntityIdentifierEqualTo(cntx2):
            return False
        if dimensionalAspectModel:
            if _DICT_SET(self.qnameDims.keys()) != _DICT_SET(
                    cntx2.qnameDims.keys()):
                return False
            for dimQname, ctx1Dim in self.qnameDims.items():
                if not ctx1Dim.isEqualTo(cntx2.qnameDims[dimQname]):
                    return False
            for nonDimVals1, nonDimVals2 in ((self.segNonDimValues,
                                              cntx2.segNonDimValues),
                                             (self.scenNonDimValues,
                                              cntx2.scenNonDimValues)):
                if len(nonDimVals1) != len(nonDimVals2):
                    return False
                for i, nonDimVal1 in enumerate(nonDimVals1):
                    if not XbrlUtil.sEqual(self.modelXbrl, nonDimVal1,
                                           nonDimVals2[i]):
                        return False
        else:
            if self.hasSegment:
                if not cntx2.hasSegment:
                    return False
                if not XbrlUtil.sEqual(self.modelXbrl, self.segment,
                                       cntx2.segment):
                    return False
            elif cntx2.hasSegment:
                return False

            if self.hasScenario:
                if not cntx2.hasScenario:
                    return False
                if not XbrlUtil.sEqual(self.modelXbrl, self.scenario,
                                       cntx2.scenario):
                    return False
            elif cntx2.hasScenario:
                return False

        return True
示例#3
0
 def isEqualTo_(self, cntx2, dimensionalAspectModel):
     """(bool) -- If dimensionalAspectModel is absent, True is assumed.  
     False means comparing based on s-equality of segment, scenario, while 
     True means based on dimensional values and nonDimensional values separately."""
     if cntx2 is None:
         return False
     if cntx2 == self:   # same context
         return True
     if (self.periodHash != cntx2.periodHash or
         self.entityIdentifierHash != cntx2.entityIdentifierHash):
         return False 
     if dimensionalAspectModel:
         if (self.dimsHash != cntx2.dimsHash or
             self.nonDimHash != cntx2.nonDimHash):
             return False
     else:
         if (self.segmentHash != cntx2.segmentHash or
             self.scenarioHash != cntx2.scenarioHash):
             return False
     if self.periodHash != cntx2.periodHash or not self.isPeriodEqualTo(cntx2) or not self.isEntityIdentifierEqualTo(cntx2):
         return False
     if dimensionalAspectModel:
         if _DICT_SET(self.qnameDims.keys()) != _DICT_SET(cntx2.qnameDims.keys()):
             return False
         for dimQname, ctx1Dim in self.qnameDims.items():
             if not ctx1Dim.isEqualTo(cntx2.qnameDims[dimQname]):
                 return False
         for nonDimVals1, nonDimVals2 in ((self.segNonDimValues,cntx2.segNonDimValues),
                                          (self.scenNonDimValues,cntx2.scenNonDimValues)):
             if len(nonDimVals1) !=  len(nonDimVals2):
                 return False
             for i, nonDimVal1 in enumerate(nonDimVals1):
                 if not XbrlUtil.sEqual(self.modelXbrl, nonDimVal1, nonDimVals2[i]):
                     return False                    
     else:
         if self.hasSegment:
             if not cntx2.hasSegment:
                 return False
             if not XbrlUtil.sEqual(self.modelXbrl, self.segment, cntx2.segment):
                 return False
         elif cntx2.hasSegment:
             return False
 
         if self.hasScenario:
             if not cntx2.hasScenario:
                 return False
             if not XbrlUtil.sEqual(self.modelXbrl, self.scenario, cntx2.scenario):
                 return False
         elif cntx2.hasScenario:
             return False
     
     return True
示例#4
0
 def isEqualTo_(self, cntx2, dimensionalAspectModel):
     if cntx2 is None:
         return False
     if cntx2 == self:   # same context
         return True
     if (self.periodHash != cntx2.periodHash or
         self.entityIdentifierHash != cntx2.entityIdentifierHash):
         return False 
     if dimensionalAspectModel:
         if (self.dimsHash != cntx2.dimsHash or
             self.nonDimHash != cntx2.nonDimHash):
             return False
     else:
         if (self.segmentHash != cntx2.segmentHash or
             self.scenarioHash != cntx2.scenarioHash):
             return False
     if self.periodHash != cntx2.periodHash or not self.isPeriodEqualTo(cntx2) or not self.isEntityIdentifierEqualTo(cntx2):
         return False
     if dimensionalAspectModel:
         if self.qnameDims.keys() != cntx2.qnameDims.keys():
             return False
         for dimQname, ctx1Dim in self.qnameDims.items():
             if not ctx1Dim.isEqualTo(cntx2.qnameDims[dimQname]):
                 return False
         for nonDimVals1, nonDimVals2 in ((self.segNonDimValues,cntx2.segNonDimValues),
                                          (self.scenNonDimValues,cntx2.scenNonDimValues)):
             if len(nonDimVals1) !=  len(nonDimVals2):
                 return False
             for i, nonDimVal1 in enumerate(nonDimVals1):
                 if not XbrlUtil.sEqual(self.modelXbrl, nonDimVal1, nonDimVals2[i]):
                     return False                    
     else:
         if self.hasSegment:
             if not cntx2.hasSegment:
                 return False
             if not XbrlUtil.sEqual(self.modelXbrl, self.segment, cntx2.segment):
                 return False
         elif cntx2.hasSegment:
             return False
 
         if self.hasScenario:
             if not cntx2.hasScenario:
                 return False
             if not XbrlUtil.sEqual(self.modelXbrl, self.scenario, cntx2.scenario):
                 return False
         elif cntx2.hasScenario:
             return False
     
     return True
示例#5
0
 def nonDimSegmentHash(self):
     try:
         return self._nonDimSegmentHash
     except AttributeError:
         self._nonDimSegmentHash = XbrlUtil.equalityHash(
             self.nonDimValues("segment"))
         return self._nonDimSegmentHash
示例#6
0
 def __hash__(self):
     if self.isExplicit:
         return hash((self.dimensionQname, self.memberQname))
     else:  # need XPath equal so that QNames aren't lexically compared (for fact and context equality in comparing formula results)
         return hash((self.dimensionQname,
                      XbrlUtil.equalityHash(XmlUtil.child(self),
                                            equalMode=XbrlUtil.XPATH_EQ)))
示例#7
0
 def nonDimScenarioHash(self):
     """(int) -- Hash, of s-equality values, of non-XDT scenario objects"""
     try:
         return self._nonDimScenarioHash
     except AttributeError:
         self._nonDimScenarioHash = XbrlUtil.equalityHash(self.nonDimValues("scenario"))
         return self._nonDimScenarioHash
示例#8
0
 def nonDimScenarioHash(self):
     try:
         return self._nonDimScenarioHash
     except AttributeError:
         self._nonDimScenarioHash = XbrlUtil.equalityHash(
             self.nonDimValues("scenario"))
         return self._nonDimScenarioHash
示例#9
0
def s_equal_test(node1, node2):
    if (isinstance(node1, (ModelFact, ModelInlineFact)) and node1.isItem and
        isinstance(node2, (ModelFact, ModelInlineFact)) and node2.isItem):
        return (c_equal_test(node1, node2) and u_equal_test(node1, node2) and
                XbrlUtil.xEqual(node1, node2) and 
                # must be validated (by xEqual) before precision tests to assure xAttributes is set
                node1.xAttributes.get("precision") == node2.xAttributes.get("precision") and
                node1.xAttributes.get("decimals") == node2.xAttributes.get("decimals"))
    elif isinstance(node1, ModelObject):
        if isinstance(node2, ModelObject):
            return XbrlUtil.sEqual(node1.modelXbrl, node1, node2, excludeIDs=XbrlUtil.TOP_IDs_EXCLUDED, dts2=node2.modelXbrl)
        else:
            return False
    elif isinstance(node1, ModelAttribute):
        if isinstance(node2, ModelAttribute):
            return node1.text == node2.text
    return False
示例#10
0
def nodes_correspond(xc, p, args):
    if len(args) != 2: raise XPathContext.FunctionNumArgs()
    node1 = nodeArg(xc, args, 0, "node()?", missingArgFallback=(), emptyFallback=())
    node2 = nodeArg(xc, args, 1, "node()?", missingArgFallback=(), emptyFallback=())
    if node1 == ():
        if node2 == (): return True
        return False
    if node2 == (): return False
    return XbrlUtil.nodesCorrespond(xc.modelXbrl, node1, node2, xc.modelXbrl)
示例#11
0
def x_equal_test(node1, node2):
    if isinstance(node1, ModelObject):
        if isinstance(node2, ModelObject):
            return XbrlUtil.xEqual(node1, node2)
        else:
            return False
    elif isinstance(node1, ModelAttribute):
        if isinstance(node2, ModelAttribute):
            return node1.sValue == node2.sValue
    return False
示例#12
0
 def isEqualTo(self, other, equalMode=XbrlUtil.XPATH_EQ):
     if isinstance(other, ModelValue.QName):
         return self.isExplicit and self.memberQname == other
     elif other is None:
         return False
     elif self.isExplicit:
         return self.memberQname == other.memberQname
     else:
         return XbrlUtil.nodesCorrespond(self.modelXbrl, self.typedMember, other.typedMember, 
                                         equalMode=equalMode, excludeIDs=XbrlUtil.NO_IDs_EXCLUDED)
示例#13
0
 def equivalenceKey(self):
     # cannot be cached because this is unique per relationship
     return (self.qname,
             self.linkQname,
             self.linkrole,  # needed when linkrole=None merges multiple links
             self.fromModelObject.objectIndex if self.fromModelObject is not None else -1,
             self.toModelObject.objectIndex if self.toModelObject is not None else -1,
             self.order,
             self.weight,
             self.preferredLabel) + \
             XbrlUtil.attributes(self.modelXbrl, self.arcElement,
                 exclusions=arcCustAttrsExclusions, keyByTag=True) # use clark tag for key instead of qname
示例#14
0
 def equivalenceKey(self):
     # cannot be cached because this is unique per relationship
     return (self.qname, 
             self.linkQname,
             self.linkrole,  # needed when linkrole=None merges multiple links
             self.fromModelObject.objectIndex if self.fromModelObject is not None else -1, 
             self.toModelObject.objectIndex if self.toModelObject is not None else -1,
             self.order, 
             self.weight, 
             self.preferredLabel) + \
             XbrlUtil.attributes(self.modelXbrl, self.arcElement, 
                 exclusions=arcCustAttrsExclusions, keyByTag=True) # use clark tag for key instead of qname
示例#15
0
 def isEqualTo(self, other, equalMode=XbrlUtil.XPATH_EQ):
     """(bool) -- True if explicit member QNames equal or typed member nodes correspond, given equalMode (s-equal, s-equal2, or xpath-equal for formula)
     
     :param equalMode: XbrlUtil.S_EQUAL (ordinary S-equality from 2.1 spec), XbrlUtil.S_EQUAL2 (XDT definition of equality, adding QName comparisions), or XbrlUtil.XPATH_EQ (XPath EQ on all types)
     """
     if other is None:
         return False
     if self.isExplicit: # other is either ModelDimensionValue or the QName value of explicit dimension
         return self.memberQname == (other.memberQname if isinstance(other, (ModelDimensionValue,DimValuePrototype)) else other)
     else: # typed dimension compared to another ModelDimensionValue or other is the value nodes
         return XbrlUtil.nodesCorrespond(self.modelXbrl, self.typedMember, 
                                         other.typedMember if isinstance(other, (ModelDimensionValue,DimValuePrototype)) else other, 
                                         equalMode=equalMode, excludeIDs=XbrlUtil.NO_IDs_EXCLUDED)
示例#16
0
 def isEqualTo(self, other, equalMode=XbrlUtil.XPATH_EQ):
     if isinstance(other, ModelValue.QName):
         return self.isExplicit and self.memberQname == other
     elif other is None:
         return False
     elif self.isExplicit:
         return self.memberQname == other.memberQname
     else:
         return XbrlUtil.nodesCorrespond(
             self.modelXbrl,
             self.typedMember,
             other.typedMember,
             equalMode=equalMode,
             excludeIDs=XbrlUtil.NO_IDs_EXCLUDED)
示例#17
0
def nodes_correspond(xc, p, args):
    if len(args) != 2: raise XPathContext.FunctionNumArgs()
    node1 = nodeArg(xc,
                    args,
                    0,
                    "node()?",
                    missingArgFallback=(),
                    emptyFallback=())
    node2 = nodeArg(xc,
                    args,
                    1,
                    "node()?",
                    missingArgFallback=(),
                    emptyFallback=())
    if node1 == ():
        if node2 == (): return True
        return False
    if node2 == (): return False
    return XbrlUtil.nodesCorrespond(xc.modelXbrl, node1, node2, xc.modelXbrl)
示例#18
0
    def validate(self):
        if not self.modelXbrl.contexts and not self.modelXbrl.facts:
            return # skip if no contexts or facts
        
        if not self.inferDecimals: # infering precision is now contrary to XBRL REC section 5.2.5.2
            self.modelXbrl.info("xbrl.5.2.5.2:inferringPrecision","Validating calculations inferring precision.")
            
        # identify equal contexts
        self.modelXbrl.profileActivity()
        uniqueContextHashes = {}
        for context in self.modelXbrl.contexts.values():
            h = context.contextDimAwareHash
            if h in uniqueContextHashes:
                if context.isEqualTo(uniqueContextHashes[h]):
                    self.mapContext[context] = uniqueContextHashes[h]
            else:
                uniqueContextHashes[h] = context
        del uniqueContextHashes
        self.modelXbrl.profileActivity("... identify equal contexts", minTimeToShow=1.0)

        # identify equal contexts
        uniqueUnitHashes = {}
        for unit in self.modelXbrl.units.values():
            h = unit.hash
            if h in uniqueUnitHashes:
                if unit.isEqualTo(uniqueUnitHashes[h]):
                    self.mapUnit[unit] = uniqueUnitHashes[h]
            else:
                uniqueUnitHashes[h] = unit
        self.modelXbrl.profileActivity("... identify equal units", minTimeToShow=1.0)
                    
        # identify concepts participating in essence-alias relationships
        # identify calcluation & essence-alias base sets (by key)
        for baseSetKey in self.modelXbrl.baseSets.keys():
            arcrole, ELR, linkqname, arcqname = baseSetKey
            if ELR and linkqname and arcqname:
                if arcrole in (XbrlConst.essenceAlias, XbrlConst.requiresElement):
                    conceptsSet = {XbrlConst.essenceAlias:self.conceptsInEssencesAlias,
                                   XbrlConst.requiresElement:self.conceptsInRequiresElement}[arcrole]
                    for modelRel in self.modelXbrl.relationshipSet(arcrole,ELR,linkqname,arcqname).modelRelationships:
                        for concept in (modelRel.fromModelObject, modelRel.toModelObject):
                            if concept is not None and concept.qname is not None:
                                conceptsSet.add(concept)
        self.modelXbrl.profileActivity("... identify requires-element and esseance-aliased concepts", minTimeToShow=1.0)

        self.bindFacts(self.modelXbrl.facts,[self.modelXbrl.modelDocument.xmlRootElement])
        self.modelXbrl.profileActivity("... bind facts", minTimeToShow=1.0)
        
        # identify calcluation & essence-alias base sets (by key)
        for baseSetKey in self.modelXbrl.baseSets.keys():
            arcrole, ELR, linkqname, arcqname = baseSetKey
            if ELR and linkqname and arcqname:
                if arcrole in (XbrlConst.summationItem, XbrlConst.essenceAlias, XbrlConst.requiresElement):
                    relsSet = self.modelXbrl.relationshipSet(arcrole,ELR,linkqname,arcqname)
                    if arcrole == XbrlConst.summationItem:
                        fromRelationships = relsSet.fromModelObjects()
                        for sumConcept, modelRels in fromRelationships.items():
                            sumBindingKeys = self.sumConceptBindKeys[sumConcept]
                            dupBindingKeys = set()
                            boundSumKeys = set()
                            # determine boundSums
                            for modelRel in modelRels:
                                itemConcept = modelRel.toModelObject
                                if itemConcept is not None and itemConcept.qname is not None:
                                    itemBindingKeys = self.itemConceptBindKeys[itemConcept]
                                    boundSumKeys |= sumBindingKeys & itemBindingKeys
                            # add up rounded items
                            boundSums = defaultdict(decimal.Decimal) # sum of facts meeting factKey
                            boundSummationItems = defaultdict(list) # corresponding fact refs for messages
                            for modelRel in modelRels:
                                weight = modelRel.weightDecimal
                                itemConcept = modelRel.toModelObject
                                if itemConcept is not None:
                                    for itemBindKey in boundSumKeys:
                                        ancestor, contextHash, unit = itemBindKey
                                        factKey = (itemConcept, ancestor, contextHash, unit)
                                        if factKey in self.itemFacts:
                                            for fact in self.itemFacts[factKey]:
                                                if fact in self.duplicatedFacts:
                                                    dupBindingKeys.add(itemBindKey)
                                                else:
                                                    roundedValue = roundFact(fact, self.inferDecimals)
                                                    boundSums[itemBindKey] += roundedValue * weight
                                                    boundSummationItems[itemBindKey].append(wrappedFactWithWeight(fact,weight,roundedValue))
                            for sumBindKey in boundSumKeys:
                                ancestor, contextHash, unit = sumBindKey
                                factKey = (sumConcept, ancestor, contextHash, unit)
                                if factKey in self.sumFacts:
                                    sumFacts = self.sumFacts[factKey]
                                    for fact in sumFacts:
                                        if fact in self.duplicatedFacts:
                                            dupBindingKeys.add(sumBindKey)
                                        elif sumBindKey not in dupBindingKeys:
                                            roundedSum = roundFact(fact, self.inferDecimals)
                                            roundedItemsSum = roundFact(fact, self.inferDecimals, vDecimal=boundSums[sumBindKey])
                                            if roundedItemsSum  != roundFact(fact, self.inferDecimals):
                                                d = inferredDecimals(fact)
                                                if isnan(d) or isinf(d): d = 4
                                                _boundSummationItems = boundSummationItems[sumBindKey]
                                                unreportedContribingItemQnames = [] # list the missing/unreported contributors in relationship order
                                                for modelRel in modelRels:
                                                    itemConcept = modelRel.toModelObject
                                                    if (itemConcept is not None and 
                                                        (itemConcept, ancestor, contextHash, unit) not in self.itemFacts):
                                                        unreportedContribingItemQnames.append(str(itemConcept.qname))
                                                self.modelXbrl.log('INCONSISTENCY', "xbrl.5.2.5.2:calcInconsistency",
                                                    _("Calculation inconsistent from %(concept)s in link role %(linkrole)s reported sum %(reportedSum)s computed sum %(computedSum)s context %(contextID)s unit %(unitID)s unreportedContributingItems %(unreportedContributors)s"),
                                                    modelObject=wrappedSummationAndItems(fact, roundedSum, _boundSummationItems),
                                                    concept=sumConcept.qname, linkrole=ELR, 
                                                    linkroleDefinition=self.modelXbrl.roleTypeDefinition(ELR),
                                                    reportedSum=Locale.format_decimal(self.modelXbrl.locale, roundedSum, 1, max(d,0)),
                                                    computedSum=Locale.format_decimal(self.modelXbrl.locale, roundedItemsSum, 1, max(d,0)), 
                                                    contextID=fact.context.id, unitID=fact.unit.id,
                                                    unreportedContributors=", ".join(unreportedContribingItemQnames) or "none")
                                                del unreportedContribingItemQnames[:]
                            boundSummationItems.clear() # dereference facts in list
                    elif arcrole == XbrlConst.essenceAlias:
                        for modelRel in relsSet.modelRelationships:
                            essenceConcept = modelRel.fromModelObject
                            aliasConcept = modelRel.toModelObject
                            essenceBindingKeys = self.esAlConceptBindKeys[essenceConcept]
                            aliasBindingKeys = self.esAlConceptBindKeys[aliasConcept]
                            for esAlBindKey in essenceBindingKeys & aliasBindingKeys:
                                ancestor, contextHash = esAlBindKey
                                essenceFactsKey = (essenceConcept, ancestor, contextHash)
                                aliasFactsKey = (aliasConcept, ancestor, contextHash)
                                if essenceFactsKey in self.esAlFacts and aliasFactsKey in self.esAlFacts:
                                    for eF in self.esAlFacts[essenceFactsKey]:
                                        for aF in self.esAlFacts[aliasFactsKey]:
                                            essenceUnit = self.mapUnit.get(eF.unit,eF.unit)
                                            aliasUnit = self.mapUnit.get(aF.unit,aF.unit)
                                            if essenceUnit != aliasUnit:
                                                self.modelXbrl.log('INCONSISTENCY', "xbrl.5.2.6.2.2:essenceAliasUnitsInconsistency",
                                                    _("Essence-Alias inconsistent units from %(essenceConcept)s to %(aliasConcept)s in link role %(linkrole)s context %(contextID)s"),
                                                    modelObject=(modelRel, eF, aF), 
                                                    essenceConcept=essenceConcept.qname, aliasConcept=aliasConcept.qname, 
                                                    linkrole=ELR, 
                                                    linkroleDefinition=self.modelXbrl.roleTypeDefinition(ELR),
                                                    contextID=eF.context.id)
                                            if not XbrlUtil.vEqual(eF, aF):
                                                self.modelXbrl.log('INCONSISTENCY', "xbrl.5.2.6.2.2:essenceAliasUnitsInconsistency",
                                                    _("Essence-Alias inconsistent value from %(essenceConcept)s to %(aliasConcept)s in link role %(linkrole)s context %(contextID)s"),
                                                    modelObject=(modelRel, eF, aF), 
                                                    essenceConcept=essenceConcept.qname, aliasConcept=aliasConcept.qname, 
                                                    linkrole=ELR,
                                                    linkroleDefinition=self.modelXbrl.roleTypeDefinition(ELR),
                                                    contextID=eF.context.id)
                    elif arcrole == XbrlConst.requiresElement:
                        for modelRel in relsSet.modelRelationships:
                            sourceConcept = modelRel.fromModelObject
                            requiredConcept = modelRel.toModelObject
                            if sourceConcept in self.requiresElementFacts and \
                               not requiredConcept in self.requiresElementFacts:
                                    self.modelXbrl.log('INCONSISTENCY', "xbrl.5.2.6.2.4:requiresElementInconsistency",
                                        _("Requires-Element %(requiringConcept)s missing required fact for %(requiredConcept)s in link role %(linkrole)s"),
                                        modelObject=sourceConcept, 
                                        requiringConcept=sourceConcept.qname, requiredConcept=requiredConcept.qname, 
                                        linkrole=ELR,
                                        linkroleDefinition=self.modelXbrl.roleTypeDefinition(ELR))
        self.modelXbrl.profileActivity("... find inconsistencies", minTimeToShow=1.0)
        self.modelXbrl.profileActivity() # reset
示例#19
0
def deep_equal(xc, p, contextItem, args):
    if len(args) != 2: raise XPathContext.FunctionNumArgs()
    return XbrlUtil.nodesCorrespond(xc.modelXbrl, args[0], args[1])
示例#20
0
    def validate(self):
        self.modelXbrl.info(
            "info",
            "Validating calculations inferring %(inferMode)s",
            inferMode=_("precision") if self.inferPrecision else _("decimals"),
        )

        # identify equal contexts
        self.modelXbrl.profileActivity()
        uniqueContextHashes = {}
        for context in self.modelXbrl.contexts.values():
            h = context.contextDimAwareHash
            if h in uniqueContextHashes:
                if context.isEqualTo(uniqueContextHashes[h]):
                    self.mapContext[context] = uniqueContextHashes[h]
            else:
                uniqueContextHashes[h] = context
        del uniqueContextHashes
        self.modelXbrl.profileActivity("... identify equal contexts", minTimeToShow=1.0)

        # identify equal contexts
        uniqueUnitHashes = {}
        for unit in self.modelXbrl.units.values():
            h = unit.hash
            if h in uniqueUnitHashes:
                if unit.isEqualTo(uniqueUnitHashes[h]):
                    self.mapUnit[unit] = uniqueUnitHashes[h]
            else:
                uniqueUnitHashes[h] = unit
        self.modelXbrl.profileActivity("... identify equal units", minTimeToShow=1.0)

        # identify concepts participating in essence-alias relationships
        # identify calcluation & essence-alias base sets (by key)
        for baseSetKey in self.modelXbrl.baseSets.keys():
            arcrole, ELR, linkqname, arcqname = baseSetKey
            if ELR and linkqname and arcqname:
                if arcrole in (XbrlConst.essenceAlias, XbrlConst.requiresElement):
                    conceptsSet = {
                        XbrlConst.essenceAlias: self.conceptsInEssencesAlias,
                        XbrlConst.requiresElement: self.conceptsInRequiresElement,
                    }[arcrole]
                    for modelRel in self.modelXbrl.relationshipSet(
                        arcrole, ELR, linkqname, arcqname
                    ).modelRelationships:
                        for concept in (modelRel.fromModelObject, modelRel.toModelObject):
                            conceptsSet.add(concept)
        self.modelXbrl.profileActivity("... identify requires-element and esseance-aliased concepts", minTimeToShow=1.0)

        self.bindFacts(self.modelXbrl.facts, [self.modelXbrl.modelDocument.xmlRootElement])
        self.modelXbrl.profileActivity("... bind facts", minTimeToShow=1.0)

        # identify calcluation & essence-alias base sets (by key)
        for baseSetKey in self.modelXbrl.baseSets.keys():
            arcrole, ELR, linkqname, arcqname = baseSetKey
            if ELR and linkqname and arcqname:
                if arcrole in (XbrlConst.summationItem, XbrlConst.essenceAlias, XbrlConst.requiresElement):
                    relsSet = self.modelXbrl.relationshipSet(arcrole, ELR, linkqname, arcqname)
                    if arcrole == XbrlConst.summationItem:
                        fromRelationships = relsSet.fromModelObjects()
                        for sumConcept, modelRels in fromRelationships.items():
                            sumBindingKeys = self.sumConceptBindKeys[sumConcept]
                            dupBindingKeys = set()
                            boundSumKeys = set()
                            # determine boundSums
                            for modelRel in modelRels:
                                itemBindingKeys = self.itemConceptBindKeys[modelRel.toModelObject]
                                boundSumKeys |= sumBindingKeys & itemBindingKeys
                            # add up rounded items
                            boundSums = defaultdict(decimal.Decimal)
                            for modelRel in modelRels:
                                weight = modelRel.weightDecimal
                                itemConcept = modelRel.toModelObject
                                for itemBindKey in boundSumKeys:
                                    ancestor, contextHash, unit = itemBindKey
                                    factKey = (itemConcept, ancestor, contextHash, unit)
                                    if factKey in self.itemFacts:
                                        for fact in self.itemFacts[factKey]:
                                            if fact in self.duplicatedFacts:
                                                dupBindingKeys.add(itemBindKey)
                                            else:
                                                boundSums[itemBindKey] += self.roundFact(fact) * weight
                            for sumBindKey in boundSumKeys:
                                ancestor, contextHash, unit = sumBindKey
                                factKey = (sumConcept, ancestor, contextHash, unit)
                                if factKey in self.sumFacts:
                                    for fact in self.sumFacts[factKey]:
                                        if fact in self.duplicatedFacts:
                                            dupBindingKeys.add(sumBindKey)
                                        elif sumBindKey not in dupBindingKeys:
                                            roundedSum = self.roundFact(fact)
                                            roundedItemsSum = self.roundFact(fact, vDecimal=boundSums[sumBindKey])
                                            if roundedItemsSum != self.roundFact(fact):
                                                self.modelXbrl.error(
                                                    "xbrl.5.2.5.2:calcInconsistency",
                                                    _(
                                                        "Calculation inconsistent from %(concept)s in link role %(linkrole)s reported sum %(reportedSum)s computed sum %(computedSum)s context %(contextID)s unit %(unitID)s"
                                                    ),
                                                    modelObject=sumConcept,
                                                    concept=sumConcept.qname,
                                                    linkrole=ELR,
                                                    reportedSum=roundedSum,
                                                    computedSum=roundedItemsSum,
                                                    contextID=context.id,
                                                    unitID=unit.id,
                                                )
                    elif arcrole == XbrlConst.essenceAlias:
                        for modelRel in relsSet.modelRelationships:
                            essenceConcept = modelRel.fromModelObject
                            aliasConcept = modelRel.toModelObject
                            essenceBindingKeys = self.esAlConceptBindKeys[essenceConcept]
                            aliasBindingKeys = self.esAlConceptBindKeys[aliasConcept]
                            for esAlBindKey in essenceBindingKeys & aliasBindingKeys:
                                ancestor, contextHash = esAlBindKey
                                essenceFactsKey = (essenceConcept, ancestor, contextHash)
                                aliasFactsKey = (aliasConcept, ancestor, contextHash)
                                if essenceFactsKey in self.esAlFacts and aliasFactsKey in self.esAlFacts:
                                    for eF in self.esAlFacts[essenceFactsKey]:
                                        for aF in self.esAlFacts[aliasFactsKey]:
                                            essenceUnit = self.mapUnit.get(eF.unit, eF.unit)
                                            aliasUnit = self.mapUnit.get(aF.unit, aF.unit)
                                            if essenceUnit != aliasUnit:
                                                self.modelXbrl.error(
                                                    "xbrl.5.2.6.2.2:essenceAliasUnitsInconsistency",
                                                    _(
                                                        "Essence-Alias inconsistent units from %(essenceConcept)s to %(aliasConcept)s in link role %(linkrole)s context %(contextID)s"
                                                    ),
                                                    modelObject=essenceConcept,
                                                    essenceConcept=essenceConcept.qname,
                                                    aliasConcept=aliasConcept.qname,
                                                    linkrole=ELR,
                                                    contextID=context.id,
                                                )
                                            if not XbrlUtil.vEqual(eF, aF):
                                                self.modelXbrl.error(
                                                    "xbrl.5.2.6.2.2:essenceAliasUnitsInconsistency",
                                                    _(
                                                        "Essence-Alias inconsistent value from %(essenceConcept)s to %(aliasConcept)s in link role %(linkrole)s context %(contextID)s"
                                                    ),
                                                    modelObject=essenceConcept,
                                                    essenceConcept=essenceConcept.qname,
                                                    aliasConcept=aliasConcept.qname,
                                                    linkrole=ELR,
                                                    contextID=context.id,
                                                )
                    elif arcrole == XbrlConst.requiresElement:
                        for modelRel in relsSet.modelRelationships:
                            sourceConcept = modelRel.fromModelObject
                            requiredConcept = modelRel.toModelObject
                            if (
                                sourceConcept in self.requiresElementFacts
                                and not requiredConcept in self.requiresElementFacts
                            ):
                                self.modelXbrl.error(
                                    "xbrl.5.2.6.2.4:requiresElementInconsistency",
                                    _(
                                        "Requires-Element %(requiringConcept)s missing required fact for %(requiredConcept)s in link role %(linkrole)s"
                                    ),
                                    modelObject=sourceConcept,
                                    requiringConcept=sourceConcept.qname,
                                    requiredConcept=requiredConcept.qname,
                                    linkrole=ELR,
                                )
        self.modelXbrl.profileActivity("... find inconsistencies", minTimeToShow=1.0)
        self.modelXbrl.profileActivity()  # reset
示例#21
0
    def validate(self):
        self.modelXbrl.error(_("Validating calculations inferring {0}")
                             .format(_("precision") if self.inferPrecision else _("decimals")))


        # identify equal contexts
        contexts = tuple(self.modelXbrl.contexts.values())
        for i in range(len(contexts)):
            cntx1 = contexts[i]
            for j in range(i+1, len(contexts)):
                cntx2 = contexts[j]
                if cntx1.isEqualTo(cntx2) and not cntx2 in self.mapContext:
                    self.mapContext[cntx2] = cntx1

        # identify equal contexts
        units = tuple(self.modelXbrl.units.values())
        for i in range(len(units)):
            unit1 = units[i]
            for j in range(i+1, len(units)):
                unit2 = units[j]
                if unit1.isEqualTo(unit2) and not unit2 in self.mapUnit:
                    self.mapUnit[unit2] = unit1
                    
        # identify concepts participating in essence-alias relationships
        # identify calcluation & essence-alias base sets (by key)
        for baseSetKey in self.modelXbrl.baseSets.keys():
            arcrole, ELR, linkqname, arcqname = baseSetKey
            if ELR and linkqname and arcqname:
                if arcrole in (XbrlConst.essenceAlias, XbrlConst.requiresElement):
                    conceptsSet = {XbrlConst.essenceAlias:self.conceptsInEssencesAlias,
                                   XbrlConst.requiresElement:self.conceptsInRequiresElement}[arcrole]
                    for modelRel in self.modelXbrl.relationshipSet(arcrole,ELR,linkqname,arcqname).modelRelationships:
                        for concept in (modelRel.fromModelObject, modelRel.toModelObject):
                            conceptsSet.add(concept)

        self.bindFacts(self.modelXbrl.facts,[self.modelXbrl.modelDocument.xmlRootElement])
        
        # identify calcluation & essence-alias base sets (by key)
        for baseSetKey in self.modelXbrl.baseSets.keys():
            arcrole, ELR, linkqname, arcqname = baseSetKey
            if ELR and linkqname and arcqname:
                if arcrole in (XbrlConst.summationItem, XbrlConst.essenceAlias, XbrlConst.requiresElement):
                    relsSet = self.modelXbrl.relationshipSet(arcrole,ELR,linkqname,arcqname)
                    if arcrole == XbrlConst.summationItem:
                        fromRelationships = relsSet.fromModelObjects()
                        for sumConcept, modelRels in fromRelationships.items():
                            sumBindingKeys = self.sumConceptBindKeys[sumConcept]
                            dupBindingKeys = set()
                            boundSumKeys = set()
                            # determine boundSums
                            for modelRel in modelRels:
                                itemBindingKeys = self.itemConceptBindKeys[modelRel.toModelObject]
                                boundSumKeys |= sumBindingKeys & itemBindingKeys
                            # add up rounded items
                            boundSums = defaultdict(float)
                            for modelRel in modelRels:
                                weight = modelRel.weight
                                itemConcept = modelRel.toModelObject
                                for itemBindKey in boundSumKeys:
                                    ancestor, context, unit = itemBindKey
                                    factKey = (itemConcept, ancestor, context, unit)
                                    if factKey in self.itemFacts:
                                        for fact in self.itemFacts[factKey]:
                                            if fact in self.duplicatedFacts:
                                                dupBindingKeys.add(itemBindKey)
                                            else:
                                                boundSums[itemBindKey] += self.roundFact(fact) * weight
                            for sumBindKey in boundSumKeys:
                                ancestor, context, unit = sumBindKey
                                factKey = (sumConcept, ancestor, context, unit)
                                if factKey in self.sumFacts:
                                    for fact in self.sumFacts[factKey]:
                                        if fact in self.duplicatedFacts:
                                            dupBindingKeys.add(sumBindKey)
                                        elif sumBindKey not in dupBindingKeys:
                                            roundedSum = self.roundFact(fact)
                                            roundedItemsSum = self.roundFact(fact, vFloat=boundSums[sumBindKey])
                                            if roundedItemsSum  != self.roundFact(fact):
                                                self.modelXbrl.error(
                                                    _("Calculation inconsistent from {0} in link role {1} reported sum {2} computed sum {3} context {4} unit {5}").format(
                                                          sumConcept.qname, ELR, roundedSum, roundedItemsSum, context.id, unit.id), 
                                                    "err", "xbrl.5.2.5.2:calcInconsistency")
                    elif arcrole == XbrlConst.essenceAlias:
                        for modelRel in relsSet.modelRelationships:
                            essenceConcept = modelRel.fromModelObject
                            aliasConcept = modelRel.toModelObject
                            essenceBindingKeys = self.esAlConceptBindKeys[essenceConcept]
                            aliasBindingKeys = self.esAlConceptBindKeys[aliasConcept]
                            for esAlBindKey in essenceBindingKeys & aliasBindingKeys:
                                ancestor, context = esAlBindKey
                                essenceFactsKey = (essenceConcept, ancestor, context)
                                aliasFactsKey = (aliasConcept, ancestor, context)
                                if essenceFactsKey in self.esAlFacts and aliasFactsKey in self.esAlFacts:
                                    for eF in self.esAlFacts[essenceFactsKey]:
                                        for aF in self.esAlFacts[aliasFactsKey]:
                                            essenceUnit = self.mapUnit.get(eF.unit,eF.unit)
                                            aliasUnit = self.mapUnit.get(aF.unit,aF.unit)
                                            if essenceUnit != aliasUnit:
                                                self.modelXbrl.error(
                                                    _("Essence-Alias inconsistent units from {0} to {1} in link role {2} context {3}").format(
                                                          essenceConcept.qname, aliasConcept.qname, ELR, context.id), 
                                                    "err", "xbrl.5.2.6.2.2:essenceAliasUnitsInconsistency")
                                            if not XbrlUtil.vEqual(essenceConcept, eF.element, aliasConcept, aF.element):
                                                self.modelXbrl.error(
                                                    _("Essence-Alias inconsistent value from {0} to {1} in link role {2} context {3}").format(
                                                          essenceConcept.qname, aliasConcept.qname, ELR, context.id), 
                                                    "err", "xbrl.5.2.6.2.2:essenceAliasUnitsInconsistency")
                    elif arcrole == XbrlConst.requiresElement:
                        for modelRel in relsSet.modelRelationships:
                            sourceConcept = modelRel.fromModelObject
                            requiredConcept = modelRel.toModelObject
                            if sourceConcept in self.requiresElementFacts and \
                               not requiredConcept in self.requiresElementFacts:
                                    self.modelXbrl.error(
                                        _("Requies-Element {0} missing required fact for {1} in link role {2}").format(
                                              sourceConcept.qname, requiredConcept.qname, ELR), 
                                        "err", "xbrl.5.2.6.2.4:requiresElementInconsistency")
示例#22
0
def aspectMatches(fact1, fact2, aspects):
    matches = True
    for aspect in (aspects if hasattr(aspects,'__iter__') else (aspects,)):
        if aspect == Aspect.LOCATION:
            if (fact1.modelXbrl == fact2.modelXbrl and # test deemed true for multi-instance comparisons
                fact1.element.parentNode != fact2.element.parentNode): matches = False
        elif aspect == Aspect.CONCEPT:
            if fact1.concept.qname != fact2.concept.qname: matches = False
        elif fact1.isTuple or fact2.isTuple:
            return True # only match the aspects both facts have 
        elif aspect == Aspect.PERIOD:
            if not fact1.context.isPeriodEqualTo(fact2.context): matches = False
        elif aspect == Aspect.ENTITY_IDENTIFIER:
            if not fact1.context.isEntityIdentifierEqualTo(fact2.context): matches = False
        elif aspect == Aspect.COMPLETE_SEGMENT:
            if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, fact1.context.segment, fact2.context.segment, dts2=fact2.modelXbrl): 
                matches = False
        elif aspect == Aspect.COMPLETE_SCENARIO:
            if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, fact1.context.scenario, fact2.context.scenario, dts2=fact2.modelXbrl): 
                matches = False
        elif aspect in (Aspect.NON_XDT_SEGMENT, Aspect.NON_XDT_SCENARIO):
            nXs1 = fact1.context.nonDimValues(aspect)
            nXs2 = fact2.context.nonDimValues(aspect)
            if len(nXs1) != len(nXs2):
                matches = False
            else:
                for i in range(len(nXs1)):
                    if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, nXs1[i], nXs2[i], dts2=fact2.modelXbrl): 
                        matches = False
                        break
        elif aspect == Aspect.UNIT:
            u1 = fact1.unit
            u2 = fact2.unit
            if (u1 is None) != (u2 is None):
                matches = False
            elif u1 and u2 and u1.measures != u2.measures:
                matches = False
        elif aspect == Aspect.DIMENSIONS:
            ''' (no implicit filtering on ALL dimensions for now)
            dimQnames1 = fact1.context.dimAspects
            dimQnames2 = fact2.context.dimAspects
            if len(dimQnames1 ^ dimQnames2):  # dims not in both
                matches = False
            else:
                for dimQname1 in dimQnames1:
                    if dimQname1 not in dimQnames2 or \
                       not aspectMatches(fact1, fact2, dimQname1):
                        matches = False
                        break
            '''
        elif isinstance(aspect, QName):
            from arelle.ModelObject import ModelDimensionValue
            dimValue1 = fact1.context.dimValue(aspect)
            dimValue2 = fact2.context.dimValue(aspect)
            if isinstance(dimValue1, ModelDimensionValue):
                if dimValue1.isExplicit: 
                    if isinstance(dimValue2, QName):
                        if dimValue1.memberQname != dimValue2:
                            matches = False
                    elif isinstance(dimValue2, ModelDimensionValue):
                        if dimValue2.isTyped:
                            matches = False
                        elif dimValue1.memberQname != dimValue2.memberQname:
                            matches = False 
                elif dimValue1.isTyped:
                    if isinstance(dimValue2, QName):
                        matches = False
                    elif isinstance(dimValue2, ModelDimensionValue):
                        if dimValue2.isExplicit:
                            matches = False
                        elif not XbrlUtil.nodesCorrespond(fact1.modelXbrl, dimValue1.typedMember, dimValue2.typedMember, dts2=fact2.modelXbrl):
                            matches = False
            elif isinstance(dimValue1,QName):
                if isinstance(dimValue2, QName):
                    if dimValue1 != dimValue2:
                        matches = False
                elif isinstance(dimValue2, ModelDimensionValue):
                    if dimValue2.isTyped:
                        matches = False
                    elif dimValue1 != dimValue2.memberQname:
                        matches = False 
            elif dimValue1 is None:
                if dimValue2:
                    matches = False
        if not matches: 
            break
    return matches
示例#23
0
 def nonDimSegmentHash(self):
     try:
         return self._nonDimSegmentHash
     except AttributeError:
         self._nonDimSegmentHash = XbrlUtil.equalityHash(self.nonDimValues("segment"))
         return self._nonDimSegmentHash
示例#24
0
 def segmentHash(self):
     # s-equality hash
     return XbrlUtil.equalityHash(self.segment)  # self-caching
示例#25
0
 def scenarioHash(self):
     """(int) -- Hash of the scenario, based on s-equality values"""
     return XbrlUtil.equalityHash( self.scenario ) # self-caching
示例#26
0
    def validate(self, modelXbrl, parameters=None):
        self.parameters = parameters
        self.NCnamePattern = re.compile(
            "^[_A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]"
            r"[_\-\."
            "\xB7A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040]*$"
        )
        self.precisionPattern = re.compile("^([0-9]+|INF)$")
        self.decimalsPattern = re.compile("^(-?[0-9]+|INF)$")
        self.isoCurrencyPattern = re.compile(r"^[A-Z]{3}$")
        self.modelXbrl = modelXbrl
        self.validateDisclosureSystem = modelXbrl.modelManager.validateDisclosureSystem
        self.disclosureSystem = modelXbrl.modelManager.disclosureSystem
        self.validateEFM = self.validateDisclosureSystem and self.disclosureSystem.EFM
        self.validateGFM = self.validateDisclosureSystem and self.disclosureSystem.GFM
        self.validateEFMorGFM = self.validateDisclosureSystem and self.disclosureSystem.EFMorGFM
        self.validateHMRC = self.validateDisclosureSystem and self.disclosureSystem.HMRC
        self.validateSBRNL = self.validateDisclosureSystem and self.disclosureSystem.SBRNL
        self.validateXmlLang = self.validateDisclosureSystem and self.disclosureSystem.xmlLangPattern
        self.validateCalcLB = modelXbrl.modelManager.validateCalcLB
        self.validateInferDecimals = modelXbrl.modelManager.validateInferDecimals

        # xlink validation
        modelXbrl.modelManager.showStatus(_("validating links"))
        modelLinks = set()
        self.remoteResourceLocElements = set()
        self.genericArcArcroles = set()
        for baseSetExtLinks in modelXbrl.baseSets.values():
            for baseSetExtLink in baseSetExtLinks:
                modelLinks.add(
                    baseSetExtLink)  # ext links are unique (no dups)
        for modelLink in modelLinks:
            fromToArcs = {}
            locLabels = {}
            resourceLabels = {}
            resourceArcTos = []
            for arcElt in modelLink.element.childNodes:
                if arcElt.nodeType == 1:
                    xlinkType = arcElt.getAttributeNS(XbrlConst.xlink, "type")
                    # locator must have an href
                    if xlinkType == "locator":
                        if not arcElt.hasAttributeNS(XbrlConst.xlink, "href"):
                            modelXbrl.error(
                                _("Linkbase {0} extended link {1} locator {2} missing href"
                                  ).format(
                                      modelLink.modelDocument.basename,
                                      modelLink.role,
                                      arcElt.hasAttributeNS(
                                          XbrlConst.xlink, "label")), "err",
                                "xlink:locatorHref")
                        locLabels[arcElt.getAttributeNS(
                            XbrlConst.xlink, "label")] = arcElt
                    elif xlinkType == "resource":
                        resourceLabels[arcElt.getAttributeNS(
                            XbrlConst.xlink, "label")] = arcElt
                    # can be no duplicated arcs between same from and to
                    elif xlinkType == "arc":
                        fromLabel = arcElt.getAttributeNS(
                            XbrlConst.xlink, "from")
                        toLabel = arcElt.getAttributeNS(XbrlConst.xlink, "to")
                        fromTo = (fromLabel, toLabel)
                        if fromTo in fromToArcs:
                            modelXbrl.error(
                                _("Linkbase {0} extended link {1} duplicate arcs from {2} to {3}"
                                  ).format(modelLink.modelDocument.basename,
                                           modelLink.role, fromLabel, toLabel),
                                "err", "xlink:dupArcs")
                        else:
                            fromToArcs[fromTo] = arcElt
                        if arcElt.namespaceURI == XbrlConst.link:
                            if arcElt.localName in arcNamesTo21Resource:  #("labelArc","referenceArc"):
                                resourceArcTos.append(
                                    (toLabel, arcElt.getAttribute("use")))
                        elif self.isGenericArc(arcElt):
                            arcrole = arcElt.getAttributeNS(
                                XbrlConst.xlink, "arcrole")
                            self.genericArcArcroles.add(arcrole)
                            if arcrole in (XbrlConst.elementLabel,
                                           XbrlConst.elementReference):
                                resourceArcTos.append((toLabel, arcrole))
                    # values of type (not needed for validating parsers)
                    if xlinkType not in xlinkTypeValues:  # ("", "simple", "extended", "locator", "arc", "resource", "title", "none"):
                        modelXbrl.error(
                            _("Linkbase {0} extended link {1} type {2} invalid"
                              ).format(modelLink.modelDocument.basename,
                                       modelLink.role, xlinkType), "err",
                            "xlink:type")
                    # values of actuate (not needed for validating parsers)
                    xlinkActuate = arcElt.getAttributeNS(
                        XbrlConst.xlink, "actuate")
                    if xlinkActuate not in xlinkActuateValues:  # ("", "onLoad", "onRequest", "other", "none"):
                        modelXbrl.error(
                            _("Linkbase {0} extended link {1} actuate {2} invalid"
                              ).format(modelLink.modelDocument.basename,
                                       modelLink.role, xlinkActuate), "err",
                            "xlink:actuate")
                    # values of show (not needed for validating parsers)
                    xlinkShow = arcElt.getAttributeNS(XbrlConst.xlink, "show")
                    if xlinkShow not in xlinkShowValues:  # ("", "new", "replace", "embed", "other", "none"):
                        modelXbrl.error(
                            _("Linkbase {0} extended link {1} show {2} invalid"
                              ).format(modelLink.modelDocument.basename,
                                       modelLink.role, xlinkShow), "err",
                            "xlink:show")
                    # values of label, from, to (not needed for validating parsers)
                    for name in xlinkLabelAttributes:  # ("label", "from", "to"):
                        value = arcElt.getAttributeNS(XbrlConst.xlink, name)
                        if value != "" and not self.NCnamePattern.match(value):
                            modelXbrl.error(
                                _("Linkbase {0} extended link {1} element {2} {3} '{4}' not an NCname"
                                  ).format(modelLink.modelDocument.basename,
                                           modelLink.role, arcElt.tagName,
                                           name, value), "err",
                                "xlink:{0}".format(name))
            # check from, to of arcs have a resource or loc
            for fromTo, arcElt in fromToArcs.items():
                fromLabel, toLabel in fromTo
                for name, value, sect in (("from", fromLabel, "3.5.3.9.2"),
                                          ("to", toLabel, "3.5.3.9.3")):
                    if value not in locLabels and value not in resourceLabels:
                        modelXbrl.error(
                            _("Arc in linkbase {0} extended link {1} from {2} to {3} attribute \"{4}\" has no matching loc or resource label"
                              ).format(modelLink.modelDocument.basename,
                                       modelLink.role, fromLabel, toLabel,
                                       name), "err",
                            "xbrl.{0}:arcResource".format(sect))
                if arcElt.localName == "footnoteArc" and arcElt.namespaceURI == XbrlConst.link and \
                   arcElt.getAttributeNS(XbrlConst.xlink,"arcrole") == XbrlConst.factFootnote:
                    if fromLabel not in locLabels:
                        modelXbrl.error(
                            _("FootnoteArc in {0} extended link {1} from {2} to {3} \"from\" is not a loc"
                              ).format(modelLink.modelDocument.basename,
                                       modelLink.role, fromLabel, toLabel),
                            "err", "xbrl.4.11.1.3.1:factFootnoteArcFrom")
                    if toLabel not in resourceLabels or qname(
                            resourceLabels[toLabel]
                    ) != XbrlConst.qnLinkFootnote:
                        modelXbrl.error(
                            _("FootnoteArc in {0} extended link {1} from {2} to {3} \"to\" is not a footnote resource"
                              ).format(modelLink.modelDocument.basename,
                                       modelLink.role, fromLabel, toLabel),
                            "err", "xbrl.4.11.1.3.1:factFootnoteArcTo")
            # check unprohibited label arcs to remote locs
            for resourceArcTo in resourceArcTos:
                resourceArcToLabel, resourceArcUse = resourceArcTo
                if resourceArcToLabel in locLabels:
                    toLabel = locLabels[resourceArcToLabel]
                    if resourceArcUse == "prohibited":
                        self.remoteResourceLocElements.add(toLabel)
                    else:
                        modelXbrl.error(
                            _("Unprohibited labelArc in linkbase {0} extended link {1} has illegal remote resource loc labeled {2} href {3}"
                              ).format(
                                  modelLink.modelDocument.basename,
                                  modelLink.role, resourceArcToLabel,
                                  toLabel.getAttributeNS(
                                      XbrlConst.xlink, "href")), "err",
                            "xbrl.5.2.2.3:labelArcRemoteResource")
                elif resourceArcToLabel in resourceLabels:
                    toResource = resourceLabels[resourceArcToLabel]
                    if resourceArcUse == XbrlConst.elementLabel:
                        if not self.isGenericLabel(toResource):
                            modelXbrl.error(
                                _("Generic label arc in linkbase {0} extended link {1} to {2} must target a generic label"
                                  ).format(modelLink.modelDocument.basename,
                                           modelLink.role, resourceArcToLabel),
                                "err", "xbrlle.2.1.1:genericLabelTarget")
                    elif resourceArcUse == XbrlConst.elementReference:
                        if not self.isGenericReference(toResource):
                            modelXbrl.error(
                                _("Generic reference arc in linkbase {0} extended link {1} to {2} must target a generic reference"
                                  ).format(modelLink.modelDocument.basename,
                                           modelLink.role, resourceArcToLabel),
                                "err", "xbrlre.2.1.1:genericReferenceTarget")

        self.dimensionDefaults = {}
        modelXbrl.qnameDimensionDefaults = {}
        modelXbrl.qnameDimensionContextElement = {}
        # check base set cycles, dimensions
        modelXbrl.modelManager.showStatus(_("validating relationship sets"))
        for baseSetKey in modelXbrl.baseSets.keys():
            arcrole, ELR, linkqname, arcqname = baseSetKey
            if arcrole.startswith("XBRL-") or ELR is None or \
                linkqname is None or arcqname is None:
                continue
            elif arcrole in XbrlConst.standardArcroleCyclesAllowed:
                cyclesAllowed, specSect = XbrlConst.standardArcroleCyclesAllowed[
                    arcrole]
            elif arcrole in self.modelXbrl.arcroleTypes and len(
                    self.modelXbrl.arcroleTypes[arcrole]) > 0:
                cyclesAllowed = self.modelXbrl.arcroleTypes[arcrole][
                    0].cyclesAllowed
                if arcrole in self.genericArcArcroles:
                    specSect = "xbrlgene:violatedCyclesConstraint"
                else:
                    specSect = "xbrl.5.1.4.3:cycles"
            else:
                cyclesAllowed = "any"
                specSect = None
            if cyclesAllowed != "any" or arcrole in (XbrlConst.summationItem,) \
                                      or arcrole in self.genericArcArcroles  \
                                      or arcrole.startswith(XbrlConst.formulaStartsWith):
                relsSet = modelXbrl.relationshipSet(arcrole, ELR, linkqname,
                                                    arcqname)
            if cyclesAllowed != "any" and \
                   (XbrlConst.isStandardExtLinkQname(linkqname) and XbrlConst.isStandardArcQname(arcqname)) \
                   or arcrole in self.genericArcArcroles:
                noUndirected = cyclesAllowed == "none"
                fromRelationships = relsSet.fromModelObjects()
                for relFrom, rels in fromRelationships.items():
                    cycleFound = self.fwdCycle(relsSet, rels, noUndirected,
                                               {relFrom})
                    if cycleFound:
                        modelXbrl.error(
                            _("Relationships have a {0} cycle in arcrole {1} link role {2} link {3}, arc {4} starting from {5}"
                              ).format(cycleFound, arcrole, ELR, linkqname,
                                       arcqname, relFrom.qname), "err",
                            "{0}".format(specSect))
                        break

            # check calculation arcs for weight issues (note calc arc is an "any" cycles)
            if arcrole == XbrlConst.summationItem:
                for modelRel in relsSet.modelRelationships:
                    weight = modelRel.weight
                    fromConcept = modelRel.fromModelObject
                    toConcept = modelRel.toModelObject
                    if fromConcept and toConcept:
                        if weight == 0:
                            modelXbrl.error(
                                _("Calculation relationship has zero weight from {0} to {1} in link role {2}"
                                  ).format(fromConcept.qname, toConcept.qname,
                                           ELR), "err",
                                "xbrl.5.2.5.2.1:zeroWeight")
                        fromBalance = fromConcept.balance
                        toBalance = toConcept.balance
                        if fromBalance and toBalance:
                            if (fromBalance == toBalance and weight < 0) or \
                               (fromBalance != toBalance and weight > 0):
                                modelXbrl.error(
                                    _("Calculation relationship has illegal weight {0} from {1}, {2}, to {3}, {4} in link role {5} (per 5.1.1.2 Table 6)"
                                      ).format(weight, fromConcept.qname,
                                               fromBalance, toConcept.qname,
                                               toBalance, ELR), "err",
                                    "xbrl.5.1.1.2:balanceCalcWeight")
                        if not fromConcept.isNumeric or not toConcept.isNumeric:
                            modelXbrl.error(
                                _("Calculation relationship has illegal concept from {0}{1} to {2}{3} in link role {4}"
                                  ).format(
                                      fromConcept.qname,
                                      "" if fromConcept.isNumeric else
                                      " (non-numeric)", toConcept.qname,
                                      "" if fromConcept.isNumeric else
                                      " (non-numeric)", ELR), "err",
                                "xbrl.5.2.5.2:nonNumericCalc")
            # check presentation relationships for preferredLabel issues
            elif arcrole == XbrlConst.parentChild:
                for modelRel in relsSet.modelRelationships:
                    preferredLabel = modelRel.preferredLabel
                    toConcept = modelRel.toModelObject
                    if preferredLabel and toConcept and \
                       toConcept.label(preferredLabel=preferredLabel,fallbackToQname=False) is None:
                        modelXbrl.error(
                            _("Presentation relationship from {0} to {1} in link role {2} missing preferredLabel {3}"
                              ).format(modelRel.fromModelObject.qname,
                                       toConcept.qname, ELR, preferredLabel),
                            "err", "xbrl.5.2.4.2.1:preferredLabelMissing")
            # check essence-alias relationships
            elif arcrole == XbrlConst.essenceAlias:
                for modelRel in relsSet.modelRelationships:
                    fromConcept = modelRel.fromModelObject
                    toConcept = modelRel.toModelObject
                    if fromConcept and toConcept:
                        if fromConcept.type != toConcept.type or fromConcept.periodType != toConcept.periodType:
                            modelXbrl.error(
                                _("Essence-alias relationship from {0} to {1} in link role {2} has different types or periodTypes"
                                  ).format(fromConcept.qname, toConcept.qname,
                                           ELR), "err",
                                "xbrl.5.2.6.2.2:essenceAliasTypes")
                        fromBalance = fromConcept.balance
                        toBalance = toConcept.balance
                        if fromBalance and toBalance:
                            if fromBalance and toBalance and fromBalance != toBalance:
                                modelXbrl.error(
                                    _("Essence-alias relationship from {0} to {1} in link role {2} has different balances"
                                      ).format(fromConcept.qname,
                                               toConcept.qname, ELR), "err",
                                    "xbrl.5.2.6.2.2:essenceAliasBalance")
            elif modelXbrl.hasXDT and arcrole.startswith(
                    XbrlConst.dimStartsWith):
                ValidateXbrlDimensions.checkBaseSet(self, arcrole, ELR,
                                                    relsSet)
            elif modelXbrl.hasFormulae and arcrole.startswith(
                    XbrlConst.formulaStartsWith):
                ValidateFormula.checkBaseSet(self, arcrole, ELR, relsSet)

        # instance checks
        modelXbrl.modelManager.showStatus(_("validating instance"))
        self.footnoteRefs = set()
        if modelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE or \
           modelXbrl.modelDocument.type == ModelDocument.Type.INLINEXBRL:
            for f in modelXbrl.facts:
                concept = f.concept
                if concept:
                    if concept.isNumeric:
                        unit = f.unit
                        if f.unitID is None or unit is None:
                            self.modelXbrl.error(
                                _("Fact {0} context {1} is numeric and must have a unit"
                                  ).format(modelXbrl.modelDocument.basename,
                                           f.qname, f.contextID), "err",
                                "xbrl.4.6.2:numericUnit")
                        else:
                            if concept.isMonetary:
                                measures = unit.measures
                                if not measures or len(measures[0]) != 1 or len(measures[1]) != 0 or \
                                    measures[0][0].namespaceURI != XbrlConst.iso4217 or \
                                    not self.isoCurrencyPattern.match(measures[0][0].localName):
                                    self.modelXbrl.error(
                                        _("Fact {0} context {1} must have a monetary unit {2}"
                                          ).format(
                                              modelXbrl.modelDocument.basename,
                                              f.qname, f.contextID, f.unitID),
                                        "err", "xbrl.4.8.2:monetaryFactUnit")
                            elif concept.isShares:
                                measures = unit.measures
                                if not measures or len(measures[0]) != 1 or len(measures[1]) != 0 or \
                                    measures[0][0] != XbrlConst.qnXbrliShares:
                                    self.modelXbrl.error(
                                        _("Fact {0} context {1} must have a xbrli:shares unit {2}"
                                          ).format(f.qname, f.contextID,
                                                   f.unitID), "err",
                                        "xbrl.4.8.2:sharesFactUnit")
                    precision = f.precision
                    hasPrecision = precision is not None
                    if hasPrecision and precision != "INF" and not precision.isdigit(
                    ):
                        self.modelXbrl.error(
                            _("Fact {0} context {1} precision {2} is invalid"
                              ).format(f.qname, f.contextID, precision), "err",
                            "xbrl.4.6.4:precision")
                    decimals = f.decimals
                    hasDecimals = decimals is not None
                    if hasPrecision and not self.precisionPattern.match(
                            precision):
                        self.modelXbrl.error(
                            _("Fact {0} context {1} precision {2} is invalid"
                              ).format(f.qname, f.contextID, precision), "err",
                            "xbrl.4.6.4:precision")
                    if hasPrecision and hasDecimals:
                        self.modelXbrl.error(
                            _("Fact {0} context {1} can not have both precision and decimals"
                              ).format(f.qname, f.contextID), "err",
                            "xbrl.4.6.3:bothPrecisionAndDecimals")
                    if hasDecimals and not self.decimalsPattern.match(
                            decimals):
                        self.modelXbrl.error(
                            _("Fact {0} context {1} decimals {2} is invalid"
                              ).format(f.qname, f.contextID, decimals), "err",
                            "xbrl.4.6.5:decimals")
                    if concept.isItem:
                        context = f.context
                        if context is None:
                            self.modelXbrl.error(
                                _("Item {0} must have a context").format(
                                    f.qname), "err",
                                "xbrl.4.6.1:itemContextRef")
                        else:
                            periodType = concept.periodType
                            if (periodType == "instant" and not context.isInstantPeriod) or \
                               (periodType == "duration" and not (context.isStartEndPeriod or context.isForeverPeriod)):
                                self.modelXbrl.error(
                                    _("Fact {0} context {1} has period type {2} conflict with context"
                                      ).format(f.qname, f.contextID,
                                               periodType), "err",
                                    "xbrl.4.7.2:contextPeriodType")
                            if modelXbrl.hasXDT:
                                ValidateXbrlDimensions.checkFact(self, f)
                        # check precision and decimals
                        if f.xsiNil == "true":
                            if hasPrecision or hasDecimals:
                                self.modelXbrl.error(
                                    _("Fact {0} context {1} can not be nil and have either precision or decimals"
                                      ).format(f.qname, f.contextID), "err",
                                    "xbrl.4.6.3:nilPrecisionDecimals")
                        elif concept.isFraction:
                            if hasPrecision or hasDecimals:
                                self.modelXbrl.error(
                                    _("Fact {0} context {1} is a fraction concept and cannot have either precision or decimals"
                                      ).format(f.qname, f.contextID), "err",
                                    "xbrl.4.6.3:fractionPrecisionDecimals")
                                numerator, denominator = f.fractionValue
                                if not (numerator == "INF"
                                        or numerator.isnumeric()):
                                    self.modelXbrl.error(
                                        _("Fact {0} context {1} is a fraction with invalid numerator {2}"
                                          ).format(f.qname, f.contextID,
                                                   numerator), "err",
                                        "xbrl.5.1.1:fractionPrecisionDecimals")
                                if not denominator.isnumeric() or int(
                                        denominator) == 0:
                                    self.modelXbrl.error(
                                        _("Fact {0} context {1} is a fraction with invalid denominator {2}"
                                          ).format(f.qname, f.contextID,
                                                   denominator), "err",
                                        "xbrl.5.1.1:fractionPrecisionDecimals")
                        else:
                            if modelXbrl.modelDocument.type != ModelDocument.Type.INLINEXBRL:
                                for child in f.element.childNodes:
                                    if child.nodeType == 1:
                                        self.modelXbrl.error(
                                            _("Fact {0} context {1} may not have child elements {2}"
                                              ).format(f.qname, f.contextID,
                                                       child.tagName), "err",
                                            "xbrl.5.1.1:itemMixedContent")
                                        break
                            if concept.isNumeric and not hasPrecision and not hasDecimals:
                                self.modelXbrl.error(
                                    _("Fact {0} context {1} is a numeric concept and must have either precision or decimals"
                                      ).format(f.qname, f.contextID), "err",
                                    "xbrl.4.6.3:missingPrecisionDecimals")
                    elif concept.isTuple:
                        if f.contextID:
                            self.modelXbrl.error(
                                _("Tuple {0} must not have a context").format(
                                    f.qname), "err",
                                "xbrl.4.6.1:tupleContextRef")
                        if hasPrecision or hasDecimals:
                            self.modelXbrl.error(
                                _("Fact {0} is a tuple and cannot have either precision or decimals"
                                  ).format(f.qname), "err",
                                "xbrl.4.6.3:tuplePrecisionDecimals")
                        # custom attributes may be allowed by anyAttribute but not by 2.1
                        for attrQname, attrValue in XbrlUtil.attributes(
                                self.modelXbrl, concept, f.element):
                            if attrQname.namespaceURI in (XbrlConst.xbrli,
                                                          XbrlConst.link,
                                                          XbrlConst.xlink,
                                                          XbrlConst.xl):
                                self.modelXbrl.error(
                                    _("Fact {0} is a tuple and must not have attribute in this namespace {1}"
                                      ).format(f.qname, attrQname), "err",
                                    "xbrl.4.9:tupleAttribute")

                    else:
                        self.modelXbrl.error(
                            _("Fact {0} must be an item or tuple").format(
                                f.qname), "err", "xbrl.4.6:notItemOrTuple")

                from arelle.ModelObject import ModelInlineFact
                if isinstance(f, ModelInlineFact):
                    self.footnoteRefs.update(f.footnoteRefs)

            #instance checks
            for cntx in modelXbrl.contexts.values():
                if cntx.isStartEndPeriod:
                    try:
                        if cntx.endDatetime <= cntx.startDatetime:
                            self.modelXbrl.error(
                                _("Context {0} must have startDate less than endDate"
                                  ).format(cntx.id), "err",
                                "xbrl.4.7.2:periodStartBeforeEnd")
                    except ValueError as err:
                        self.modelXbrl.error(
                            _("Context {0} startDate or endDate: {1}").format(
                                cntx.id, err), "err",
                            "xbrl.4.7.2:contextDateError")
                elif cntx.isInstantPeriod:
                    try:
                        cntx.instantDatetime  #parse field
                    except ValueError as err:
                        self.modelXbrl.error(
                            _("Context {0} instant date: {1}").format(
                                cntx.id, err), "err",
                            "xbrl.4.7.2:contextDateError")
                self.segmentScenario(cntx.segment, cntx.id, "segment",
                                     "4.7.3.2")
                self.segmentScenario(cntx.scenario, cntx.id, "scenario",
                                     "4.7.4")
                if modelXbrl.hasXDT:
                    ValidateXbrlDimensions.checkContext(self, cntx)

            for unit in modelXbrl.units.values():
                mulDivMeasures = unit.measures
                if mulDivMeasures:
                    for measures in mulDivMeasures:
                        for measure in measures:
                            if measure.namespaceURI == XbrlConst.xbrli and not \
                                measure in (XbrlConst.qnXbrliPure, XbrlConst.qnXbrliShares):
                                self.modelXbrl.error(
                                    _("Unit {0} illegal measure: {1}").format(
                                        unit.id, measure), "err",
                                    "xbrl.4.8.2:measureElement")
                    for numeratorMeasure in mulDivMeasures[0]:
                        if numeratorMeasure in mulDivMeasures[1]:
                            self.modelXbrl.error(
                                _("Unit {0} numerator measure: {1} also appears as denominator measure"
                                  ).format(unit.id, numeratorMeasure), "err",
                                "xbrl.4.8.4:measureBothNumDenom")

        #concepts checks
        modelXbrl.modelManager.showStatus(_("validating concepts"))
        for concept in modelXbrl.qnameConcepts.values():
            conceptType = concept.type
            if XbrlConst.isStandardNamespace(concept.namespaceURI) or \
               not concept.modelDocument.inDTS:
                continue

            if concept.isTuple:
                # must be global
                if not concept.element.parentNode.localName == "schema":
                    self.modelXbrl.error(
                        _("Tuple {0} must be declared globally").format(
                            concept.qname), "err",
                        "xbrl.4.9:tupleGloballyDeclared")
                if concept.periodType:
                    self.modelXbrl.error(
                        _("Tuple {0} must not have periodType").format(
                            concept.qname), "err", "xbrl.4.9:tuplePeriodType")
                if concept.balance:
                    self.modelXbrl.error(
                        _("Tuple {0} must not have balance").format(
                            concept.qname), "err", "xbrl.4.9:tupleBalance")
                # check attribute declarations
                for attributeQname in conceptType.attributes:
                    if attributeQname.namespaceURI in (XbrlConst.xbrli,
                                                       XbrlConst.link,
                                                       XbrlConst.xlink,
                                                       XbrlConst.xl):
                        self.modelXbrl.error(
                            _("Tuple {0} must not have attribute in this namespace {1}"
                              ).format(concept.qname, attributeQname), "err",
                            "xbrl.4.9:tupleAttribute")
                # check for mixed="true" or simple content
                if XmlUtil.descendantAttr(conceptType.element, XbrlConst.xsd,
                                          ("complexType", "complexContent"),
                                          "mixed") == "true":
                    self.modelXbrl.error(
                        _("Tuple {0} must not have mixed content").format(
                            concept.qname), "err",
                        "xbrl.4.9:tupleMixedContent")
                if XmlUtil.descendant(conceptType.element, XbrlConst.xsd,
                                      "simpleContent"):
                    self.modelXbrl.error(
                        _("Tuple {0} must not have simple content").format(
                            concept.qname), "err",
                        "xbrl.4.9:tupleSimpleContent")
                # child elements must be item or tuple
                for elementQname in conceptType.elements:
                    childConcept = self.modelXbrl.qnameConcepts.get(
                        elementQname)
                    if childConcept is None:
                        self.modelXbrl.error(
                            _("Tuple {0} element {1} not defined").format(
                                concept.qname, elementQname), "err",
                            "xbrl.4.9:tupleElementUndefined")
                    elif not (
                            childConcept.isItem or childConcept.isTuple
                            or  # isItem/isTuple do not include item or tuple itself
                            childConcept.qname == XbrlConst.qnXbrliItem
                            or  # subs group includes item as member
                            childConcept.qname == XbrlConst.qnXbrliTuple):
                        self.modelXbrl.error(
                            _("Tuple {0} must not have element {1} not an item or tuple"
                              ).format(concept.qname, elementQname), "err",
                            "xbrl.4.9:tupleElementItemOrTuple")
            elif concept.isItem:
                if concept.periodType not in periodTypeValues:  #("instant","duration"):
                    self.modelXbrl.error(
                        _("Item {0} must have a valid periodType").format(
                            concept.qname), "err",
                        "xbrl.5.1.1.1:itemPeriodType")
                if concept.isMonetary:
                    if concept.balance not in balanceValues:  #(None, "credit","debit"):
                        self.modelXbrl.error(
                            _("Item {0} must have a valid balance {1}").format(
                                concept.qname, concept.balance), "err",
                            "xbrl.5.1.1.2:itemBalance")
                else:
                    if concept.balance:
                        self.modelXbrl.error(
                            _("Item {0} may not have a balance").format(
                                concept.qname), "err",
                            "xbrl.5.1.1.2:itemBalance")
                if concept.baseXbrliType not in baseXbrliTypes:
                    self.modelXbrl.error(
                        _("Item {0} type {1} invalid").format(
                            concept.qname, concept.baseXbrliType), "err",
                        "xbrl.5.1.1.3:itemType")
                if modelXbrl.hasXDT:
                    if concept.isHypercubeItem and not concept.abstract == "true":
                        self.modelXbrl.error(
                            _("Hypercube item {0} must be abstract").format(
                                concept.qname), "err",
                            "xbrldte:HypercubeElementIsNotAbstractError")
                    elif concept.isDimensionItem and not concept.abstract == "true":
                        self.modelXbrl.error(
                            _("Dimension item {0} must be abstract").format(
                                concept.qname), "err",
                            "xbrldte:DimensionElementIsNotAbstractError")
            if modelXbrl.hasXDT:
                ValidateXbrlDimensions.checkConcept(self, concept)

        modelXbrl.modelManager.showStatus(_("validating DTS"))
        self.DTSreferenceResourceIDs = {}
        ValidateXbrlDTS.checkDTS(self, modelXbrl.modelDocument, [])
        del self.DTSreferenceResourceIDs

        if self.validateCalcLB:
            modelXbrl.modelManager.showStatus(
                _("Validating instance calculations"))
            ValidateXbrlCalcs.validate(
                modelXbrl, inferPrecision=(not self.validateInferDecimals))

        if modelXbrl.modelManager.validateUtr:
            ValidateUtr.validate(modelXbrl)

        if modelXbrl.hasFormulae:
            ValidateFormula.validate(self)

        modelXbrl.modelManager.showStatus(_("ready"), 2000)
示例#27
0
 def segmentHash(self):
     # s-equality hash
     return XbrlUtil.equalityHash( self.segment ) # self-caching
示例#28
0
    def validate(self, modelXbrl, parameters=None):
        self.parameters = parameters
        self.precisionPattern = re.compile("^([0-9]+|INF)$")
        self.decimalsPattern = re.compile("^(-?[0-9]+|INF)$")
        self.isoCurrencyPattern = re.compile(r"^[A-Z]{3}$")
        self.modelXbrl = modelXbrl
        self.validateDisclosureSystem = modelXbrl.modelManager.validateDisclosureSystem
        self.disclosureSystem = modelXbrl.modelManager.disclosureSystem
        self.validateEFM = self.validateDisclosureSystem and self.disclosureSystem.EFM
        self.validateGFM = self.validateDisclosureSystem and self.disclosureSystem.GFM
        self.validateEFMorGFM = self.validateDisclosureSystem and self.disclosureSystem.EFMorGFM
        self.validateHMRC = self.validateDisclosureSystem and self.disclosureSystem.HMRC
        self.validateSBRNL = self.validateDisclosureSystem and self.disclosureSystem.SBRNL
        self.validateXmlLang = self.validateDisclosureSystem and self.disclosureSystem.xmlLangPattern
        self.validateCalcLB = modelXbrl.modelManager.validateCalcLB
        self.validateInferDecimals = modelXbrl.modelManager.validateInferDecimals
        
        # xlink validation
        modelXbrl.modelManager.showStatus(_("validating links"))
        modelLinks = set()
        self.remoteResourceLocElements = set()
        self.genericArcArcroles = set()
        for baseSetExtLinks in modelXbrl.baseSets.values():
            for baseSetExtLink in baseSetExtLinks:
                modelLinks.add(baseSetExtLink)    # ext links are unique (no dups)
        for modelLink in modelLinks:
            fromToArcs = {}
            locLabels = {}
            resourceLabels = {}
            resourceArcTos = []
            for arcElt in modelLink.iterchildren():
                if isinstance(arcElt,ModelObject):
                    xlinkType = arcElt.get("{http://www.w3.org/1999/xlink}type")
                    # locator must have an href
                    if xlinkType == "locator":
                        if arcElt.get("{http://www.w3.org/1999/xlink}href") is None:
                            modelXbrl.error("xlink:locatorHref",
                                _("Xlink locator %(xlinkLabel)s missing href in extended link %(linkrole)s"),
                                modelObject=arcElt,
                                linkrole=modelLink.role, 
                                xlinkLabel=arcElt.get("{http://www.w3.org/1999/xlink}label")) 
                        locLabels[arcElt.get("{http://www.w3.org/1999/xlink}label")] = arcElt
                    elif xlinkType == "resource":
                        resourceLabels[arcElt.get("{http://www.w3.org/1999/xlink}label")] = arcElt
                    # can be no duplicated arcs between same from and to
                    elif xlinkType == "arc":
                        fromLabel = arcElt.get("{http://www.w3.org/1999/xlink}from")
                        toLabel = arcElt.get("{http://www.w3.org/1999/xlink}to")
                        fromTo = (fromLabel,toLabel)
                        if fromTo in fromToArcs:
                            modelXbrl.error("xlink:dupArcs",
                                _("Duplicate xlink arcs  in extended link %(linkrole)s from %(xlinkLabelFrom)s to %(xlinkLabelTo)s"),
                                modelObject=arcElt,
                                linkrole=modelLink.role, 
                                xlinkLabelFrom=fromLabel, xlinkLabelTo=toLabel)
                        else:
                            fromToArcs[fromTo] = arcElt
                        if arcElt.namespaceURI == XbrlConst.link:
                            if arcElt.localName in arcNamesTo21Resource: #("labelArc","referenceArc"):
                                resourceArcTos.append((toLabel, arcElt.get("use"), arcElt))
                        elif self.isGenericArc(arcElt):
                            arcrole = arcElt.get("{http://www.w3.org/1999/xlink}arcrole")
                            self.genericArcArcroles.add(arcrole)
                            if arcrole in (XbrlConst.elementLabel, XbrlConst.elementReference):
                                resourceArcTos.append((toLabel, arcrole, arcElt))
                    # values of type (not needed for validating parsers)
                    if xlinkType not in xlinkTypeValues: # ("", "simple", "extended", "locator", "arc", "resource", "title", "none"):
                        modelXbrl.error("xlink:type",
                            _("Xlink type %(xlinkType)s invalid in extended link %(linkrole)s"),
                            modelObject=arcElt, linkrole=modelLink.role, xlinkType=xlinkType)
                    # values of actuate (not needed for validating parsers)
                    xlinkActuate = arcElt.get("{http://www.w3.org/1999/xlink}actuate")
                    if xlinkActuate not in xlinkActuateValues: # ("", "onLoad", "onRequest", "other", "none"):
                        modelXbrl.error("xlink:actuate",
                            _("Actuate %(xlinkActuate)s invalid in extended link %(linkrole)s"),
                            modelObject=arcElt, linkrole=modelLink.role, xlinkActuate=xlinkActuate)
                    # values of show (not needed for validating parsers)
                    xlinkShow = arcElt.get("{http://www.w3.org/1999/xlink}show")
                    if xlinkShow not in xlinkShowValues: # ("", "new", "replace", "embed", "other", "none"):
                        modelXbrl.error("xlink:show",
                            _("Show %(xlinkShow)s invalid in extended link %(linkrole)s"),
                            modelObject=arcElt, linkrole=modelLink.role, xlinkShow=xlinkShow)
            # check from, to of arcs have a resource or loc
            for fromTo, arcElt in fromToArcs.items():
                fromLabel, toLabel in fromTo
                for name, value, sect in (("from", fromLabel, "3.5.3.9.2"),("to",toLabel, "3.5.3.9.3")):
                    if value not in locLabels and value not in resourceLabels:
                        modelXbrl.error("xbrl.{0}:arcResource".format(sect),
                            _("Arc in extended link %(linkrole)s from %(xlinkLabelFrom)s to %(xlinkLabelTo)s attribute '%(attribute)s' has no matching loc or resource label"),
                            modelObject=arcElt, 
                            linkrole=modelLink.role, xlinkLabelFrom=fromLabel, xlinkLabelTo=toLabel, 
                            attribute=name)
                if arcElt.localName == "footnoteArc" and arcElt.namespaceURI == XbrlConst.link and \
                   arcElt.get("{http://www.w3.org/1999/xlink}arcrole") == XbrlConst.factFootnote:
                    if fromLabel not in locLabels:
                        modelXbrl.error("xbrl.4.11.1.3.1:factFootnoteArcFrom",
                            _("Footnote arc in extended link %(linkrole)s from %(xlinkLabelFrom)s to %(xlinkLabelTo)s \"from\" is not a loc"),
                            modelObject=arcElt, 
                            linkrole=modelLink.role, xlinkLabelFrom=fromLabel, xlinkLabelTo=toLabel)
                    if toLabel not in resourceLabels or qname(resourceLabels[toLabel]) != XbrlConst.qnLinkFootnote:
                        modelXbrl.error("xbrl.4.11.1.3.1:factFootnoteArcTo",
                            _("Footnote arc in extended link %(linkrole)s from %(xlinkLabelFrom)s to %(xlinkLabelTo)s \"to\" is not a footnote resource"),
                            modelObject=arcElt, 
                            linkrole=modelLink.role, xlinkLabelFrom=fromLabel, xlinkLabelTo=toLabel)
            # check unprohibited label arcs to remote locs
            for resourceArcTo in resourceArcTos:
                resourceArcToLabel, resourceArcUse, arcElt = resourceArcTo
                if resourceArcToLabel in locLabels:
                    toLabel = locLabels[resourceArcToLabel]
                    if resourceArcUse == "prohibited":
                        self.remoteResourceLocElements.add(toLabel)
                    else:
                        modelXbrl.error("xbrl.5.2.2.3:labelArcRemoteResource",
                            _("Unprohibited labelArc in extended link %(linkrole)s has illegal remote resource loc labeled %(xlinkLabel)s href %(xlinkHref)s"),
                            modelObject=arcElt, 
                            linkrole=modelLink.role, 
                            xlinkLabel=resourceArcToLabel,
                            xlinkHref=toLabel.get("{http://www.w3.org/1999/xlink}href"))
                elif resourceArcToLabel in resourceLabels:
                    toResource = resourceLabels[resourceArcToLabel]
                    if resourceArcUse == XbrlConst.elementLabel:
                        if not self.isGenericLabel(toResource):
                            modelXbrl.error("xbrlle.2.1.1:genericLabelTarget",
                                _("Generic label arc in extended link %(linkrole)s to %(xlinkLabel)s must target a generic label"),
                                modelObject=arcElt, 
                                linkrole=modelLink.role, 
                                xlinkLabel=resourceArcToLabel)
                    elif resourceArcUse == XbrlConst.elementReference:
                        if not self.isGenericReference(toResource):
                            modelXbrl.error("xbrlre.2.1.1:genericReferenceTarget",
                                _("Generic reference arc in extended link %(linkrole)s to %(xlinkLabel)s must target a generic reference"),
                                modelObject=arcElt, 
                                linkrole=modelLink.role, 
                                xlinkLabel=resourceArcToLabel)
            resourceArcTos = None # dereference arcs

        modelXbrl.dimensionDefaultConcepts = {}
        modelXbrl.qnameDimensionDefaults = {}
        modelXbrl.qnameDimensionContextElement = {}
        # check base set cycles, dimensions
        modelXbrl.modelManager.showStatus(_("validating relationship sets"))
        for baseSetKey in modelXbrl.baseSets.keys():
            arcrole, ELR, linkqname, arcqname = baseSetKey
            if arcrole.startswith("XBRL-") or ELR is None or \
                linkqname is None or arcqname is None:
                continue
            elif arcrole in XbrlConst.standardArcroleCyclesAllowed:
                # TODO: table should be in this module, where it is used
                cyclesAllowed, specSect = XbrlConst.standardArcroleCyclesAllowed[arcrole]
            elif arcrole in self.modelXbrl.arcroleTypes and len(self.modelXbrl.arcroleTypes[arcrole]) > 0:
                cyclesAllowed = self.modelXbrl.arcroleTypes[arcrole][0].cyclesAllowed
                if arcrole in self.genericArcArcroles:
                    specSect = "xbrlgene:violatedCyclesConstraint"
                else:
                    specSect = "xbrl.5.1.4.3:cycles"
            else:
                cyclesAllowed = "any"
                specSect = None
            if cyclesAllowed != "any" or arcrole in (XbrlConst.summationItem,) \
                                      or arcrole in self.genericArcArcroles  \
                                      or arcrole.startswith(XbrlConst.formulaStartsWith):
                relsSet = modelXbrl.relationshipSet(arcrole,ELR,linkqname,arcqname)
            if cyclesAllowed != "any" and \
                   (XbrlConst.isStandardExtLinkQname(linkqname) and XbrlConst.isStandardArcQname(arcqname)) \
                   or arcrole in self.genericArcArcroles:
                noUndirected = cyclesAllowed == "none"
                fromRelationships = relsSet.fromModelObjects()
                for relFrom, rels in fromRelationships.items():
                    cycleFound = self.fwdCycle(relsSet, rels, noUndirected, {relFrom})
                    if cycleFound is not None:
                        path = str(relFrom.qname) + " " + " - ".join(
                            "{0}:{1} {2}".format(rel.modelDocument.basename, rel.sourceline, rel.toModelObject.qname)
                            for rel in reversed(cycleFound[1:]))
                        modelXbrl.error(specSect,
                            _("Relationships have a %(cycle)s cycle in arcrole %(arcrole)s \nlink role %(linkrole)s \nlink %(linkname)s, \narc %(arcname)s, \npath %(path)s"),
                            modelObject=cycleFound[1], cycle=cycleFound[0], path=path,
                            arcrole=arcrole, linkrole=ELR, linkname=linkqname, arcname=arcqname), 
                        break
                
            # check calculation arcs for weight issues (note calc arc is an "any" cycles)
            if arcrole == XbrlConst.summationItem:
                for modelRel in relsSet.modelRelationships:
                    weight = modelRel.weight
                    fromConcept = modelRel.fromModelObject
                    toConcept = modelRel.toModelObject
                    if fromConcept is not None and toConcept is not None:
                        if weight == 0:
                            modelXbrl.error("xbrl.5.2.5.2.1:zeroWeight",
                                _("Calculation relationship has zero weight from %(source)s to %(target)s in link role %(linkrole)s"),
                                modelObject=modelRel,
                                source=fromConcept.qname, target=toConcept.qname, linkrole=ELR), 
                        fromBalance = fromConcept.balance
                        toBalance = toConcept.balance
                        if fromBalance and toBalance:
                            if (fromBalance == toBalance and weight < 0) or \
                               (fromBalance != toBalance and weight > 0):
                                modelXbrl.error("xbrl.5.1.1.2:balanceCalcWeight",
                                    _("Calculation relationship has illegal weight %(weight)s from %(source)s, %(sourceBalance)s, to %(target)s, %(targetBalance)s, in link role %(linkrole)s (per 5.1.1.2 Table 6)"),
                                    modelObject=modelRel, weight=weight,
                                    source=fromConcept.qname, target=toConcept.qname, linkrole=ELR, 
                                    sourceBalance=fromBalance, targetBalance=toBalance)
                        if not fromConcept.isNumeric or not toConcept.isNumeric:
                            modelXbrl.error("xbrl.5.2.5.2:nonNumericCalc",
                                _("Calculation relationship has illegal concept from %(source)s%(sourceNumericDecorator)s to %(target)s%(targetNumericDecorator)s in link role %(linkrole)s"),
                                modelObject=modelRel,
                                source=fromConcept.qname, target=toConcept.qname, linkrole=ELR, 
                                sourceNumericDecorator="" if fromConcept.isNumeric else _(" (non-numeric)"), 
                                targetNumericDecorator="" if toConcept.isNumeric else _(" (non-numeric)"))
            # check presentation relationships for preferredLabel issues
            elif arcrole == XbrlConst.parentChild:
                for modelRel in relsSet.modelRelationships:
                    preferredLabel = modelRel.preferredLabel
                    toConcept = modelRel.toModelObject
                    if preferredLabel is not None and toConcept is not None and \
                       toConcept.label(preferredLabel=preferredLabel,fallbackToQname=False) is None:
                        modelXbrl.error("xbrl.5.2.4.2.1:preferredLabelMissing",
                            _("Presentation relationship from %(source)s to %(target)s in link role %(linkrole)s missing preferredLabel %(preferredLabel)s"),
                            modelObject=modelRel,
                            source=modelRel.fromModelObject.qname, target=toConcept.qname, linkrole=ELR, 
                            preferredLabel=preferredLabel)
            # check essence-alias relationships
            elif arcrole == XbrlConst.essenceAlias:
                for modelRel in relsSet.modelRelationships:
                    fromConcept = modelRel.fromModelObject
                    toConcept = modelRel.toModelObject
                    if fromConcept is not None and toConcept is not None:
                        if fromConcept.type != toConcept.type or fromConcept.periodType != toConcept.periodType:
                            modelXbrl.error("xbrl.5.2.6.2.2:essenceAliasTypes",
                                _("Essence-alias relationship from %(source)s to %(target)s in link role %(linkrole)s has different types or periodTypes"),
                                modelObject=modelRel,
                                source=fromConcept.qname, target=toConcept.qname, linkrole=ELR)
                        fromBalance = fromConcept.balance
                        toBalance = toConcept.balance
                        if fromBalance and toBalance:
                            if fromBalance and toBalance and fromBalance != toBalance:
                                modelXbrl.error("xbrl.5.2.6.2.2:essenceAliasBalance",
                                    _("Essence-alias relationship from %(source)s to %(target)s in link role %(linkrole)s has different balances")).format(
                                    modelObject=modelRel,
                                    source=fromConcept.qname, target=toConcept.qname, linkrole=ELR)
            elif modelXbrl.hasXDT and arcrole.startswith(XbrlConst.dimStartsWith):
                ValidateXbrlDimensions.checkBaseSet(self, arcrole, ELR, relsSet)             
            elif modelXbrl.hasFormulae and arcrole.startswith(XbrlConst.formulaStartsWith):
                ValidateFormula.checkBaseSet(self, arcrole, ELR, relsSet)
                            
        # instance checks
        modelXbrl.modelManager.showStatus(_("validating instance"))
        self.footnoteRefs = set()
        if modelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE or \
           modelXbrl.modelDocument.type == ModelDocument.Type.INLINEXBRL:
            for f in modelXbrl.facts:
                concept = f.concept
                if concept is not None:
                    if concept.isNumeric:
                        unit = f.unit
                        if f.unitID is None or unit is None:
                            self.modelXbrl.error("xbrl.4.6.2:numericUnit",
                                 _("Fact %(fact)s context %(contextID)s is numeric and must have a unit"),
                                 modelObject=f, fact=f.qname, contextID=f.contextID)
                        else:
                            if concept.isMonetary:
                                measures = unit.measures
                                if not measures or len(measures[0]) != 1 or len(measures[1]) != 0 or \
                                    measures[0][0].namespaceURI != XbrlConst.iso4217 or \
                                    not self.isoCurrencyPattern.match(measures[0][0].localName):
                                        self.modelXbrl.error("xbrl.4.8.2:monetaryFactUnit",
                                            _("Fact %(fact)s context %(contextID)s must have a monetary unit %(unitID)s"),
                                             modelObject=f, fact=f.qname, contextID=f.contextID, unitID=f.unitID)
                            elif concept.isShares:
                                measures = unit.measures
                                if not measures or len(measures[0]) != 1 or len(measures[1]) != 0 or \
                                    measures[0][0] != XbrlConst.qnXbrliShares:
                                        self.modelXbrl.error("xbrl.4.8.2:sharesFactUnit",
                                            _("Fact %(fact)s context %(contextID)s must have a xbrli:shares unit %(unitID)s"),
                                            modelObject=f, fact=f.qname, contextID=f.contextID, unitID=f.unitID)
                    precision = f.precision
                    hasPrecision = precision is not None
                    if hasPrecision and precision != "INF" and not precision.isdigit():
                        self.modelXbrl.error("xbrl.4.6.4:precision",
                            _("Fact %(fact)s context %(contextID)s precision %(precision)s is invalid"),
                            modelObject=f, fact=f.qname, contextID=f.contextID, precision=precision)
                    decimals = f.decimals
                    hasDecimals = decimals is not None
                    if hasPrecision and not self.precisionPattern.match(precision):
                        self.modelXbrl.error("xbrl.4.6.4:precision",
                            _("Fact %(fact)s context %(contextID)s precision %(precision)s is invalid"),
                            modelObject=f, fact=f.qname, contextID=f.contextID, precision=precision)
                    if hasPrecision and hasDecimals:
                        self.modelXbrl.error("xbrl.4.6.3:bothPrecisionAndDecimals",
                            _("Fact %(fact)s context %(contextID)s can not have both precision and decimals"),
                            modelObject=f, fact=f.qname, contextID=f.contextID)
                    if hasDecimals and not self.decimalsPattern.match(decimals):
                        self.modelXbrl.error(_("xbrl.4.6.5:decimals"),
                            _("Fact %(fact)s context %(contextID)s decimals %(decimals)s is invalid"),
                            modelObject=f, fact=f.qname, contextID=f.contextID, decimals=decimals)
                    if concept.isItem:
                        context = f.context
                        if context is None:
                            self.modelXbrl.error("xbrl.4.6.1:itemContextRef",
                                _("Item %(fact)s must have a context"),
                                modelObject=f, fact=f.qname)
                        else:
                            periodType = concept.periodType
                            if (periodType == "instant" and not context.isInstantPeriod) or \
                               (periodType == "duration" and not (context.isStartEndPeriod or context.isForeverPeriod)):
                                self.modelXbrl.error("xbrl.4.7.2:contextPeriodType",
                                    _("Fact %(fact)s context %(contextID)s has period type %(periodType)s conflict with context"),
                                    modelObject=f, fact=f.qname, contextID=f.contextID, periodType=periodType)
                            if modelXbrl.hasXDT:
                                ValidateXbrlDimensions.checkFact(self, f)
                        # check precision and decimals
                        if f.xsiNil == "true":
                            if hasPrecision or hasDecimals:
                                self.modelXbrl.error("xbrl.4.6.3:nilPrecisionDecimals",
                                    _("Fact %(fact)s context %(contextID)s can not be nil and have either precision or decimals"),
                                    modelObject=f, fact=f.qname, contextID=f.contextID)
                        elif concept.isFraction:
                            if hasPrecision or hasDecimals:
                                self.modelXbrl.error("xbrl.4.6.3:fractionPrecisionDecimals",
                                    _("Fact %(fact)s context %(contextID)s is a fraction concept and cannot have either precision or decimals"),
                                    modelObject=f, fact=f.qname, contextID=f.contextID)
                                numerator, denominator = f.fractionValue
                                if not (numerator == "INF" or numerator.isnumeric()):
                                    self.modelXbrl.error("xbrl.5.1.1:fractionPrecisionDecimals",
                                        _("Fact %(fact)s context %(contextID)s is a fraction with invalid numerator %(numerator)s"),
                                        modelObject=f, fact=f.qname, contextID=f.contextID, numerator=numerator)
                                if not denominator.isnumeric() or int(denominator) == 0:
                                    self.modelXbrl.error("xbrl.5.1.1:fractionPrecisionDecimals",
                                        _("Fact %(fact)s context %(contextID)s is a fraction with invalid denominator %(denominator)")).format(
                                        modelObject=f, fact=f.qname, contextID=f.contextID, denominator=denominator)
                        else:
                            if modelXbrl.modelDocument.type != ModelDocument.Type.INLINEXBRL:
                                for child in f.iterchildren():
                                    if isinstance(child,ModelObject):
                                        self.modelXbrl.error("xbrl.5.1.1:itemMixedContent",
                                            _("Fact %(fact)s context %(contextID)s may not have child elements %(childElementName)s"),
                                            modelObject=f, fact=f.qname, contextID=f.contextID, childElementName=child.prefixedName)
                                        break
                            if concept.isNumeric and not hasPrecision and not hasDecimals:
                                self.modelXbrl.error("xbrl.4.6.3:missingPrecisionDecimals",
                                    _("Fact %(fact)s context %(contextID)s is a numeric concept and must have either precision or decimals"),
                                    modelObject=f, fact=f.qname, contextID=f.contextID)
                    elif concept.isTuple:
                        if f.contextID:
                            self.modelXbrl.error("xbrl.4.6.1:tupleContextRef",
                                _("Tuple %(fact)s must not have a context"),
                                modelObject=f, fact=f.qname)
                        if hasPrecision or hasDecimals:
                            self.modelXbrl.error("xbrl.4.6.3:tuplePrecisionDecimals",
                                _("Fact %(fact)s is a tuple and cannot have either precision or decimals"),
                                modelObject=f, fact=f.qname)
                        # custom attributes may be allowed by anyAttribute but not by 2.1
                        for attrQname, attrValue in XbrlUtil.attributes(self.modelXbrl, f):
                            if attrQname.namespaceURI in (XbrlConst.xbrli, XbrlConst.link, XbrlConst.xlink, XbrlConst.xl):
                                self.modelXbrl.error(_("xbrl.4.9:tupleAttribute"),
                                    _("Fact %(fact)s is a tuple and must not have attribute in this namespace %(attribute)s"),
                                    modelObject=f, fact=f.qname, attribute=attrQname), 
                    else:
                        self.modelXbrl.error("xbrl.4.6:notItemOrTuple",
                            _("Fact %(fact)s must be an item or tuple"),
                            modelObject=f, fact=f.qname)
                        
                if isinstance(f, ModelInlineFact):
                    self.footnoteRefs.update(f.footnoteRefs)
            
            #instance checks
            for cntx in modelXbrl.contexts.values():
                if cntx.isStartEndPeriod:
                    try:
                        if cntx.endDatetime <= cntx.startDatetime:
                            self.modelXbrl.error("xbrl.4.7.2:periodStartBeforeEnd",
                                _("Context %(contextID)s must have startDate less than endDate"),
                                modelObject=cntx, contextID=cntx.id)
                    except (TypeError, ValueError) as err:
                        self.modelXbrl.error("xbrl.4.7.2:contextDateError",
                            _("Context %(contextID) startDate or endDate: %(error)s"),
                            modelObject=cntx, contextID=cntx.id, error=err)
                elif cntx.isInstantPeriod:
                    try:
                        cntx.instantDatetime #parse field
                    except ValueError as err:
                        self.modelXbrl.error("xbrl.4.7.2:contextDateError",
                            _("Context %(contextID)s instant date: %(error)s"),
                            modelObject=cntx, contextID=cntx.id, error=err)
                self.segmentScenario(cntx.segment, cntx.id, "segment", "4.7.3.2")
                self.segmentScenario(cntx.scenario, cntx.id, "scenario", "4.7.4")
                if modelXbrl.hasXDT:
                    ValidateXbrlDimensions.checkContext(self,cntx)
                
            for unit in modelXbrl.units.values():
                mulDivMeasures = unit.measures
                if mulDivMeasures:
                    for measures in mulDivMeasures:
                        for measure in measures:
                            if measure.namespaceURI == XbrlConst.xbrli and not \
                                measure in (XbrlConst.qnXbrliPure, XbrlConst.qnXbrliShares):
                                    self.modelXbrl.error("xbrl.4.8.2:measureElement",
                                        _("Unit %(unitID)s illegal measure: %(measure)s"),
                                        modelObject=unit, unitID=unit.id, measure=measure)
                    for numeratorMeasure in mulDivMeasures[0]:
                        if numeratorMeasure in mulDivMeasures[1]:
                            self.modelXbrl.error("xbrl.4.8.4:measureBothNumDenom",
                                _("Unit %(unitID)s numerator measure: %(measure)s also appears as denominator measure"),
                                modelObject=unit, unitID=unit.id, measure=numeratorMeasure)
                    
        #concepts checks
        modelXbrl.modelManager.showStatus(_("validating concepts"))
        for concept in modelXbrl.qnameConcepts.values():
            conceptType = concept.type
            if XbrlConst.isStandardNamespace(concept.qname.namespaceURI) or \
               not concept.modelDocument.inDTS:
                continue
            
            if concept.isTuple:
                # must be global
                if not concept.getparent().localName == "schema":
                    self.modelXbrl.error("xbrl.4.9:tupleGloballyDeclared",
                        _("Tuple %(concept)s must be declared globally"),
                        modelObject=concept, concept=concept.qname)
                if concept.periodType:
                    self.modelXbrl.error("xbrl.4.9:tuplePeriodType",
                        _("Tuple %(concept)s must not have periodType"),
                        modelObject=concept, concept=concept.qname)
                if concept.balance:
                    self.modelXbrl.error("xbrl.4.9:tupleBalance",
                        _("Tuple %(concept)s must not have balance"),
                        modelObject=concept, concept=concept.qname)
                if conceptType is not None:
                    # check attribute declarations
                    for attribute in conceptType.attributes.values():
                        if attribute.qname.namespaceURI in (XbrlConst.xbrli, XbrlConst.link, XbrlConst.xlink, XbrlConst.xl):
                            self.modelXbrl.error("xbrl.4.9:tupleAttribute",
                                _("Tuple %(concept)s must not have attribute in this namespace %(attribute)s"),
                                modelObject=concept, concept=concept.qname, attribute=attribute.qname)
                    # check for mixed="true" or simple content
                    if XmlUtil.descendantAttr(conceptType, XbrlConst.xsd, ("complexType", "complexContent"), "mixed") == "true":
                        self.modelXbrl.error("xbrl.4.9:tupleMixedContent",
                            _("Tuple %(concept)s must not have mixed content"),
                            modelObject=concept, concept=concept.qname)
                    if XmlUtil.descendant(conceptType, XbrlConst.xsd, "simpleContent"):
                        self.modelXbrl.error("xbrl.4.9:tupleSimpleContent",
                            _("Tuple %(concept)s must not have simple content"),
                            modelObject=concept, concept=concept.qname)
                    # child elements must be item or tuple
                    for elementQname in conceptType.elements:
                        childConcept = self.modelXbrl.qnameConcepts.get(elementQname)
                        if childConcept is None:
                            self.modelXbrl.error("xbrl.4.9:tupleElementUndefined",
                                _("Tuple %(concept)s element %(tupleElement)s not defined"),
                                modelObject=concept, concept=str(concept.qname), tupleElement=elementQname)
                        elif not (childConcept.isItem or childConcept.isTuple or # isItem/isTuple do not include item or tuple itself
                                  childConcept.qname == XbrlConst.qnXbrliItem or # subs group includes item as member
                                  childConcept.qname == XbrlConst.qnXbrliTuple):
                            self.modelXbrl.error("xbrl.4.9:tupleElementItemOrTuple",
                                _("Tuple %(concept)s must not have element %(tupleElement)s not an item or tuple"),
                                modelObject=concept, concept=concept.qname, tupleElement=elementQname)
            elif concept.isItem:
                if concept.periodType not in periodTypeValues: #("instant","duration"):
                    self.modelXbrl.error("xbrl.5.1.1.1:itemPeriodType",
                        _("Item %(concept)s must have a valid periodType"),
                        modelObject=concept, concept=concept.qname)
                if concept.isMonetary:
                    if concept.balance not in balanceValues: #(None, "credit","debit"):
                        self.modelXbrl.error("xbrl.5.1.1.2:itemBalance",
                            _("Item %(concept)s must have a valid balance %(balance)s"),
                            modelObject=concept, concept=concept.qname, balance=concept.balance)
                else:
                    if concept.balance:
                        self.modelXbrl.error("xbrl.5.1.1.2:itemBalance",
                            _("Item %(concept)s may not have a balance"),
                            modelObject=concept, concept=concept.qname)
                if concept.baseXbrliType not in baseXbrliTypes:
                    self.modelXbrl.error("xbrl.5.1.1.3:itemType",
                        _("Item %(concept)s type %(itemType)s invalid"),
                        modelObject=concept, concept=concept.qname, itemType=concept.baseXbrliType)
                if modelXbrl.hasXDT:
                    if concept.isHypercubeItem and not concept.abstract == "true":
                        self.modelXbrl.error("xbrldte:HypercubeElementIsNotAbstractError",
                            _("Hypercube item %(concept)s must be abstract"),
                            modelObject=concept, concept=concept.qname)
                    elif concept.isDimensionItem and not concept.abstract == "true":
                        self.modelXbrl.error("xbrldte:DimensionElementIsNotAbstractError",
                            _("Dimension item %(concept)s must be abstract"),
                            modelObject=concept, concept=concept.qname)
            if modelXbrl.hasXDT:
                ValidateXbrlDimensions.checkConcept(self, concept)
            
        modelXbrl.modelManager.showStatus(_("validating DTS"))
        self.DTSreferenceResourceIDs = {}
        ValidateXbrlDTS.checkDTS(self, modelXbrl.modelDocument, [])
        del self.DTSreferenceResourceIDs
        
        if self.validateCalcLB:
            modelXbrl.modelManager.showStatus(_("Validating instance calculations"))
            ValidateXbrlCalcs.validate(modelXbrl, inferPrecision=(not self.validateInferDecimals))
            
        if (modelXbrl.modelManager.validateUtr or
            (self.validateEFM and 
             any((concept.namespaceURI in self.disclosureSystem.standardTaxonomiesDict) 
                 for concept in self.modelXbrl.nameConcepts.get("UTR",())))):
            ValidateUtr.validate(modelXbrl)
            
        if modelXbrl.hasFormulae:
            ValidateFormula.validate(self)
            
        modelXbrl.modelManager.showStatus(_("ready"), 2000)
示例#29
0
 def scenarioHash(self):
     # s-equality hash
     return XbrlUtil.equalityHash( self.scenario ) # self-caching
示例#30
0
 def scenarioHash(self):
     # s-equality hash
     return XbrlUtil.equalityHash(self.scenario)  # self-caching
示例#31
0
 def segmentHash(self):
     """(int) -- Hash of the segment, based on s-equality values"""
     return XbrlUtil.equalityHash( self.segment ) # self-caching
示例#32
0
 def checkFacts(self, facts, inTuple=False):  # do in document order
     for f in facts:
         concept = f.concept
         if concept is not None:
             if concept.isNumeric:
                 unit = f.unit
                 if f.unitID is None or unit is None:
                     self.modelXbrl.error("xbrl.4.6.2:numericUnit",
                          _("Fact %(fact)s context %(contextID)s is numeric and must have a unit"),
                          modelObject=f, fact=f.qname, contextID=f.contextID)
                 else:
                     if concept.isMonetary:
                         measures = unit.measures
                         if not measures or len(measures[0]) != 1 or len(measures[1]) != 0:
                             self.modelXbrl.error("xbrl.4.8.2:monetaryFactUnit-notSingleMeasure",
                                 _("Fact %(fact)s context %(contextID)s must have a single unit measure which is monetary %(unitID)s"),
                                  modelObject=f, fact=f.qname, contextID=f.contextID, unitID=f.unitID)
                         elif (measures[0][0].namespaceURI != XbrlConst.iso4217 or
                               not self.isoCurrencyPattern.match(measures[0][0].localName)):
                             self.modelXbrl.error("xbrl.4.8.2:monetaryFactUnit-notMonetaryMeasure",
                                 _("Fact %(fact)s context %(contextID)s must have a monetary unit measure %(unitID)s"),
                                  modelObject=f, fact=f.qname, contextID=f.contextID, unitID=f.unitID)
                     elif concept.isShares:
                         measures = unit.measures
                         if not measures or len(measures[0]) != 1 or len(measures[1]) != 0:
                             self.modelXbrl.error("xbrl.4.8.2:sharesFactUnit-notSingleMeasure",
                                 _("Fact %(fact)s context %(contextID)s must have a single xbrli:shares unit %(unitID)s"),
                                 modelObject=f, fact=f.qname, contextID=f.contextID, unitID=f.unitID)
                         elif measures[0][0] != XbrlConst.qnXbrliShares:
                             self.modelXbrl.error("xbrl.4.8.2:sharesFactUnit-notSharesMeasure",
                                 _("Fact %(fact)s context %(contextID)s must have a xbrli:shares unit %(unitID)s"),
                                 modelObject=f, fact=f.qname, contextID=f.contextID, unitID=f.unitID)
             precision = f.precision
             hasPrecision = precision is not None
             if hasPrecision and precision != "INF" and not precision.isdigit():
                 self.modelXbrl.error("xbrl.4.6.4:precision",
                     _("Fact %(fact)s context %(contextID)s precision %(precision)s is invalid"),
                     modelObject=f, fact=f.qname, contextID=f.contextID, precision=precision)
             decimals = f.decimals
             hasDecimals = decimals is not None
             if hasPrecision and not self.precisionPattern.match(precision):
                 self.modelXbrl.error("xbrl.4.6.4:precision",
                     _("Fact %(fact)s context %(contextID)s precision %(precision)s is invalid"),
                     modelObject=f, fact=f.qname, contextID=f.contextID, precision=precision)
             if hasPrecision and hasDecimals:
                 self.modelXbrl.error("xbrl.4.6.3:bothPrecisionAndDecimals",
                     _("Fact %(fact)s context %(contextID)s can not have both precision and decimals"),
                     modelObject=f, fact=f.qname, contextID=f.contextID)
             if hasDecimals and not self.decimalsPattern.match(decimals):
                 self.modelXbrl.error(_("xbrl.4.6.5:decimals"),
                     _("Fact %(fact)s context %(contextID)s decimals %(decimals)s is invalid"),
                     modelObject=f, fact=f.qname, contextID=f.contextID, decimals=decimals)
             if concept.isItem:
                 context = f.context
                 if context is None:
                     self.modelXbrl.error("xbrl.4.6.1:itemContextRef",
                         _("Item %(fact)s must have a context"),
                         modelObject=f, fact=f.qname)
                 else:
                     periodType = concept.periodType
                     if (periodType == "instant" and not context.isInstantPeriod) or \
                        (periodType == "duration" and not (context.isStartEndPeriod or context.isForeverPeriod)):
                         self.modelXbrl.error("xbrl.4.7.2:contextPeriodType",
                             _("Fact %(fact)s context %(contextID)s has period type %(periodType)s conflict with context"),
                             modelObject=f, fact=f.qname, contextID=f.contextID, periodType=periodType)
                         
                 # check precision and decimals
                 if f.xsiNil == "true":
                     if hasPrecision or hasDecimals:
                         self.modelXbrl.error("xbrl.4.6.3:nilPrecisionDecimals",
                             _("Fact %(fact)s context %(contextID)s can not be nil and have either precision or decimals"),
                             modelObject=f, fact=f.qname, contextID=f.contextID)
                 elif concept.isFraction:
                     if hasPrecision or hasDecimals:
                         self.modelXbrl.error("xbrl.4.6.3:fractionPrecisionDecimals",
                             _("Fact %(fact)s context %(contextID)s is a fraction concept and cannot have either precision or decimals"),
                             modelObject=f, fact=f.qname, contextID=f.contextID)
                         numerator, denominator = f.fractionValue
                         if not (numerator == "INF" or numerator.isnumeric()):
                             self.modelXbrl.error("xbrl.5.1.1:fractionPrecisionDecimals",
                                 _("Fact %(fact)s context %(contextID)s is a fraction with invalid numerator %(numerator)s"),
                                 modelObject=f, fact=f.qname, contextID=f.contextID, numerator=numerator)
                         if not denominator.isnumeric() or _INT(denominator) == 0:
                             self.modelXbrl.error("xbrl.5.1.1:fractionPrecisionDecimals",
                                 _("Fact %(fact)s context %(contextID)s is a fraction with invalid denominator %(denominator)")).format(
                                 modelObject=f, fact=f.qname, contextID=f.contextID, denominator=denominator)
                 else:
                     if self.modelXbrl.modelDocument.type != ModelDocument.Type.INLINEXBRL:
                         for child in f.iterchildren():
                             if isinstance(child,ModelObject):
                                 self.modelXbrl.error("xbrl.5.1.1:itemMixedContent",
                                     _("Fact %(fact)s context %(contextID)s may not have child elements %(childElementName)s"),
                                     modelObject=f, fact=f.qname, contextID=f.contextID, childElementName=child.prefixedName)
                                 break
                     if concept.isNumeric and not hasPrecision and not hasDecimals:
                         self.modelXbrl.error("xbrl.4.6.3:missingPrecisionDecimals",
                             _("Fact %(fact)s context %(contextID)s is a numeric concept and must have either precision or decimals"),
                             modelObject=f, fact=f.qname, contextID=f.contextID)
             elif concept.isTuple:
                 if f.contextID:
                     self.modelXbrl.error("xbrl.4.6.1:tupleContextRef",
                         _("Tuple %(fact)s must not have a context"),
                         modelObject=f, fact=f.qname)
                 if hasPrecision or hasDecimals:
                     self.modelXbrl.error("xbrl.4.6.3:tuplePrecisionDecimals",
                         _("Fact %(fact)s is a tuple and cannot have either precision or decimals"),
                         modelObject=f, fact=f.qname)
                 # custom attributes may be allowed by anyAttribute but not by 2.1
                 for attrQname, attrValue in XbrlUtil.attributes(self.modelXbrl, f):
                     if attrQname.namespaceURI in (XbrlConst.xbrli, XbrlConst.link, XbrlConst.xlink, XbrlConst.xl):
                         self.modelXbrl.error(_("xbrl.4.9:tupleAttribute"),
                             _("Fact %(fact)s is a tuple and must not have attribute in this namespace %(attribute)s"),
                             modelObject=f, fact=f.qname, attribute=attrQname), 
             else:
                 self.modelXbrl.error("xbrl.4.6:notItemOrTuple",
                     _("Fact %(fact)s must be an item or tuple"),
                     modelObject=f, fact=f.qname)
                 
         if isinstance(f, ModelInlineFact):
             if concept is None:
                 self.modelXbrl.error("xbrl:schemaImportMissing",
                         _("Fact %(fact)s missing schema definition or missing name attribute"),
                         modelObject=f, fact=f.qname)
             if f.localName in {"fraction", "nonFraction", "nonNumeric"} and not f.contextID:
                 self.modelXbrl.error("ix:missingContextRef",
                     _("Fact %(fact)s is missing a contextRef"),
                     modelObject=f, fact=f.qname)
             if f.localName in {"fraction", "nonFraction"} and not f.unitID:
                 self.modelXbrl.error("ix:missingUnitRef",
                     _("Fact %(fact)s is missing a unitRef"),
                     modelObject=f, fact=f.qname)
             self.footnoteRefs.update(f.footnoteRefs)
             fmt = f.format
             if fmt:
                 if fmt.namespaceURI not in FunctionIxt.ixtNamespaceURIs:
                     self.modelXbrl.error("ix.14.2:invalidTransformation",
                         _("Fact %(fact)s has unrecognized transformation namespace %(namespace)s"),
                         modelObject=f, fact=f.qname, namespace=fmt.namespaceURI)
                 elif fmt.localName not in FunctionIxt.ixtFunctions:
                     self.modelXbrl.error("ix.14.2:invalidTransformation",
                         _("Fact %(fact)s has unrecognized transformation name %(name)s"),
                         modelObject=f, fact=f.qname, name=fmt.localName)
                 if fmt.namespaceURI == FunctionIxt.deprecatedNamespaceURI:
                     self.factsWithDeprecatedIxNamespace.append(f)
             if f.isTuple or f.tupleID:
                 self.checkIxTupleContent(f, set())
             if not inTuple and f.order is not None: 
                 self.modelXbrl.error("ix.13.1.2:tupleOrder",
                     _("Fact %(fact)s must not have an order (%(order)s) unless in a tuple"),
                     modelObject=f, fact=f.qname, order=f.order)
         if f.modelTupleFacts:
             self.checkFacts(f.modelTupleFacts, inTuple=True)
示例#33
0
def aspectMatches(xpCtx, fact1, fact2, aspects):
    if fact1 is None or fact2 is None:  # fallback (atomic) never matches any aspect
        return False
    matches = True
    for aspect in (aspects if hasattr(aspects,'__iter__') else (aspects,)):
        if aspect == Aspect.LOCATION:
            if (fact1.modelXbrl == fact2.modelXbrl and # test deemed true for multi-instance comparisons
                fact1.getparent() != fact2.getparent()): matches = False
        elif aspect == Aspect.CONCEPT:
            if fact1.concept.qname != fact2.concept.qname: matches = False
        elif fact1.isTuple or fact2.isTuple:
            return True # only match the aspects both facts have 
        elif aspect == Aspect.PERIOD:
            if not fact1.context.isPeriodEqualTo(fact2.context): matches = False
        elif aspect == Aspect.ENTITY_IDENTIFIER:
            if not fact1.context.isEntityIdentifierEqualTo(fact2.context): matches = False
        elif aspect == Aspect.COMPLETE_SEGMENT:
            if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, fact1.context.segment, fact2.context.segment, dts2=fact2.modelXbrl): 
                matches = False
        elif aspect == Aspect.COMPLETE_SCENARIO:
            if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, fact1.context.scenario, fact2.context.scenario, dts2=fact2.modelXbrl): 
                matches = False
        elif aspect in (Aspect.NON_XDT_SEGMENT, Aspect.NON_XDT_SCENARIO):
            nXs1 = fact1.context.nonDimValues(aspect)
            nXs2 = fact2.context.nonDimValues(aspect)
            if len(nXs1) != len(nXs2):
                matches = False
            else:
                for i in range(len(nXs1)):
                    if not XbrlUtil.nodesCorrespond(fact1.modelXbrl, nXs1[i], nXs2[i], dts2=fact2.modelXbrl): 
                        matches = False
                        break
        elif aspect == Aspect.UNIT:
            u1 = fact1.unit
            u2 = fact2.unit
            if (u1 is None) != (u2 is None):
                matches = False
            elif u1 is not None and u2 is not None and u1.measures != u2.measures:
                matches = False
        elif aspect == Aspect.DIMENSIONS:
            ''' (no implicit filtering on ALL dimensions for now)
            dimQnames1 = fact1.context.dimAspects
            dimQnames2 = fact2.context.dimAspects
            if len(dimQnames1 ^ dimQnames2):  # dims not in both
                matches = False
            else:
                for dimQname1 in dimQnames1:
                    if dimQname1 not in dimQnames2 or \
                       not aspectMatches(fact1, fact2, dimQname1):
                        matches = False
                        break
            '''
        elif isinstance(aspect, QName):
            from arelle.ModelInstanceObject import ModelDimensionValue
            dimValue1 = fact1.context.dimValue(aspect)
            dimValue2 = fact2.context.dimValue(aspect)
            if isinstance(dimValue1, ModelDimensionValue):
                if dimValue1.isExplicit: 
                    if isinstance(dimValue2, QName):
                        if dimValue1.memberQname != dimValue2:
                            matches = False
                    elif isinstance(dimValue2, ModelDimensionValue):
                        if dimValue2.isTyped:
                            matches = False
                        elif dimValue1.memberQname != dimValue2.memberQname:
                            matches = False 
                    elif dimValue2 is None:
                        matches = False
                elif dimValue1.isTyped:
                    if isinstance(dimValue2, QName):
                        matches = False
                    elif isinstance(dimValue2, ModelDimensionValue):
                        if dimValue2.isExplicit:
                            matches = False
                        elif dimValue1.dimension.typedDomainElement in xpCtx.modelXbrl.modelFormulaEqualityDefinitions:
                            equalityDefinition = xpCtx.modelXbrl.modelFormulaEqualityDefinitions[dimValue1.dimension.typedDomainElement]
                            matches = equalityDefinition.evalTest(xpCtx, fact1, fact2)
                        elif not XbrlUtil.nodesCorrespond(fact1.modelXbrl, dimValue1.typedMember, dimValue2.typedMember, dts2=fact2.modelXbrl):
                            matches = False
                    elif dimValue2 is None:
                        matches = False
            elif isinstance(dimValue1,QName): # first dim is default value of an explicit dim
                if isinstance(dimValue2, QName): # second dim is default value of an explicit dim
                    # multi-instance does not consider member's qname here where it is a default
                    # only check if qnames match if the facts are from same instance
                    if fact1.modelXbrl == fact2.modelXbrl and dimValue1 != dimValue2:
                        matches = False
                elif isinstance(dimValue2, ModelDimensionValue):
                    if dimValue2.isTyped:
                        matches = False
                    elif dimValue1 != dimValue2.memberQname:
                        matches = False 
                elif dimValue2 is None: # no dim aspect for fact 2
                    if fact1.modelXbrl == fact2.modelXbrl: # only allowed for multi-instance
                        matches = False
            elif dimValue1 is None:
                # absent dim member from fact1 allowed if fact2 is default in different instance
                if isinstance(dimValue2,QName):
                    if fact1.modelXbrl == fact2.modelXbrl:
                        matches = False
                elif dimValue2 is not None:
                    matches = False
                # else if both are None, matches True for single and multiple instance
        if not matches: 
            break
    return matches
示例#34
0
def aspectMatches(fact1, fact2, aspects):
    matches = True
    for aspect in (aspects if hasattr(aspects, '__iter__') else (aspects, )):
        if aspect == Aspect.LOCATION:
            if (fact1.modelXbrl == fact2.modelXbrl
                    and  # test deemed true for multi-instance comparisons
                    fact1.element.parentNode != fact2.element.parentNode):
                matches = False
        elif aspect == Aspect.CONCEPT:
            if fact1.concept.qname != fact2.concept.qname: matches = False
        elif fact1.isTuple or fact2.isTuple:
            return True  # only match the aspects both facts have
        elif aspect == Aspect.PERIOD:
            if not fact1.context.isPeriodEqualTo(fact2.context):
                matches = False
        elif aspect == Aspect.ENTITY_IDENTIFIER:
            if not fact1.context.isEntityIdentifierEqualTo(fact2.context):
                matches = False
        elif aspect == Aspect.COMPLETE_SEGMENT:
            if not XbrlUtil.nodesCorrespond(fact1.modelXbrl,
                                            fact1.context.segment,
                                            fact2.context.segment,
                                            dts2=fact2.modelXbrl):
                matches = False
        elif aspect == Aspect.COMPLETE_SCENARIO:
            if not XbrlUtil.nodesCorrespond(fact1.modelXbrl,
                                            fact1.context.scenario,
                                            fact2.context.scenario,
                                            dts2=fact2.modelXbrl):
                matches = False
        elif aspect in (Aspect.NON_XDT_SEGMENT, Aspect.NON_XDT_SCENARIO):
            nXs1 = fact1.context.nonDimValues(aspect)
            nXs2 = fact2.context.nonDimValues(aspect)
            if len(nXs1) != len(nXs2):
                matches = False
            else:
                for i in range(len(nXs1)):
                    if not XbrlUtil.nodesCorrespond(fact1.modelXbrl,
                                                    nXs1[i],
                                                    nXs2[i],
                                                    dts2=fact2.modelXbrl):
                        matches = False
                        break
        elif aspect == Aspect.UNIT:
            u1 = fact1.unit
            u2 = fact2.unit
            if (u1 is None) != (u2 is None):
                matches = False
            elif u1 and u2 and u1.measures != u2.measures:
                matches = False
        elif aspect == Aspect.DIMENSIONS:
            ''' (no implicit filtering on ALL dimensions for now)
            dimQnames1 = fact1.context.dimAspects
            dimQnames2 = fact2.context.dimAspects
            if len(dimQnames1 ^ dimQnames2):  # dims not in both
                matches = False
            else:
                for dimQname1 in dimQnames1:
                    if dimQname1 not in dimQnames2 or \
                       not aspectMatches(fact1, fact2, dimQname1):
                        matches = False
                        break
            '''
        elif isinstance(aspect, QName):
            from arelle.ModelObject import ModelDimensionValue
            dimValue1 = fact1.context.dimValue(aspect)
            dimValue2 = fact2.context.dimValue(aspect)
            if isinstance(dimValue1, ModelDimensionValue):
                if dimValue1.isExplicit:
                    if isinstance(dimValue2, QName):
                        if dimValue1.memberQname != dimValue2:
                            matches = False
                    elif isinstance(dimValue2, ModelDimensionValue):
                        if dimValue2.isTyped:
                            matches = False
                        elif dimValue1.memberQname != dimValue2.memberQname:
                            matches = False
                elif dimValue1.isTyped:
                    if isinstance(dimValue2, QName):
                        matches = False
                    elif isinstance(dimValue2, ModelDimensionValue):
                        if dimValue2.isExplicit:
                            matches = False
                        elif not XbrlUtil.nodesCorrespond(
                                fact1.modelXbrl,
                                dimValue1.typedMember,
                                dimValue2.typedMember,
                                dts2=fact2.modelXbrl):
                            matches = False
            elif isinstance(dimValue1, QName):
                if isinstance(dimValue2, QName):
                    if dimValue1 != dimValue2:
                        matches = False
                elif isinstance(dimValue2, ModelDimensionValue):
                    if dimValue2.isTyped:
                        matches = False
                    elif dimValue1 != dimValue2.memberQname:
                        matches = False
            elif dimValue1 is None:
                if dimValue2:
                    matches = False
        if not matches:
            break
    return matches
示例#35
0
 def __hash__(self):
     if self.isExplicit:
         return hash( (self.dimensionQname, self.memberQname) )
     else: # need XPath equal so that QNames aren't lexically compared (for fact and context equality in comparing formula results)
         return hash( (self.dimensionQname, XbrlUtil.equalityHash(XmlUtil.child(self), equalMode=XbrlUtil.XPATH_EQ)) )
示例#36
0
 def nonDimScenarioHash(self):
     try:
         return self._nonDimScenarioHash
     except AttributeError:
         self._nonDimScenarioHash = XbrlUtil.equalityHash(self.nonDimValues("scenario"))
         return self._nonDimScenarioHash