Example #1
0
 def isVEqualTo(self, other, deemP0Equal=False):
     """(bool) -- v-equality of two facts
     
     Note that facts may be in different instances
     """
     if self.isTuple or other.isTuple:
         return False
     if self.isNil:
         return other.isNil
     if other.isNil:
         return False
     if not self.context.isEqualTo(other.context):
         return False
     if self.concept.isNumeric:
         if other.concept.isNumeric:
             if not self.unit.isEqualTo(other.unit):
                 return False
             if self.modelXbrl.modelManager.validateInferDecimals:
                 d = min((inferredDecimals(self), inferredDecimals(other))); p = None
                 if isnan(d) and deemP0Equal:
                     return True
             else:
                 d = None; p = min((inferredPrecision(self), inferredPrecision(other)))
                 if p == 0 and deemP0Equal:
                     return True
             return roundValue(self.value,precision=p,decimals=d) == roundValue(other.value,precision=p,decimals=d)
         else:
             return False
     selfValue = self.value
     otherValue = other.value
     if isinstance(selfValue,str) and isinstance(otherValue,str):
         return selfValue.strip() == otherValue.strip()
     else:
         return selfValue == otherValue
Example #2
0
 def isVEqualTo(self, other):
     if self.isTuple or other.isTuple:
         return False
     if self.isNil:
         return other.isNil
     if other.isNil:
         return False
     if not self.context.isEqualTo(other.context):
         return False
     if self.concept.isNumeric:
         if other.concept.isNumeric:
             if not self.unit.isEqualTo(other.unit):
                 return False
             if self.modelXbrl.modelManager.validateInferDecimals:
                 d = min((inferredDecimals(self), inferredDecimals(other))); p = None
             else:
                 d = None; p = min((inferredPrecision(self), inferredPrecision(other)))
             return roundValue(float(self.value),precision=p,decimals=d) == roundValue(float(other.value),precision=p,decimals=d)
         else:
             return False
     selfValue = self.value
     otherValue = other.value
     if isinstance(selfValue,str) and isinstance(otherValue,str):
         return selfValue.strip() == otherValue.strip()
     else:
         return selfValue == otherValue
Example #3
0
def generateInfoset(dts, infosetFile):
    if dts.fileSource.isArchive:
        return
    import os, io
    from arelle import XmlUtil, XbrlConst
    from arelle.ValidateXbrlCalcs import inferredPrecision, inferredDecimals            
    
    XmlUtil.setXmlns(dts.modelDocument, "ptv", "http://www.xbrl.org/2003/ptv")
    
    numFacts = 0
    
    for fact in dts.facts:
        try:
            if fact.concept.periodType:
                fact.set("{http://www.xbrl.org/2003/ptv}periodType", fact.concept.periodType)
            if fact.concept.balance:
                fact.set("{http://www.xbrl.org/2003/ptv}balance", fact.concept.balance)
            if fact.isNumeric and not fact.isNil:
                fact.set("{http://www.xbrl.org/2003/ptv}decimals", str(inferredDecimals(fact)))
                fact.set("{http://www.xbrl.org/2003/ptv}precision", str(inferredPrecision(fact)))
            numFacts += 1
        except Exception as err:
            dts.error("saveInfoset.exception",
                     _("Facts exception %(fact)s %(value)s %(error)s."),
                     modelObject=fact, fact=fact.qname, value=fact.effectiveValue, error = err)

    fh = open(infosetFile, "w", encoding="utf-8")
    XmlUtil.writexml(fh, dts.modelDocument.xmlDocument, encoding="utf-8")
    fh.close()
    
    dts.info("info:saveInfoset",
             _("Infoset of %(entryFile)s has %(numberOfFacts)s facts in infoset file %(infosetOutputFile)s."),
             modelObject=dts,
             entryFile=dts.uri, numberOfFacts=numFacts, infosetOutputFile=infosetFile)
def generateInstanceInfoset(dts, instanceInfosetFile):
    if dts.fileSource.isArchive:
        return
    import os, io
    from arelle import XmlUtil, XbrlConst
    from arelle.ValidateXbrlCalcs import inferredPrecision, inferredDecimals            
    
    XmlUtil.setXmlns(dts.modelDocument, u"ptv", u"http://www.xbrl.org/2003/ptv")
    
    numFacts = 0
    
    for fact in dts.facts:
        try:
            if fact.concept.periodType:
                fact.set(u"{http://www.xbrl.org/2003/ptv}periodType", fact.concept.periodType)
            if fact.concept.balance:
                fact.set(u"{http://www.xbrl.org/2003/ptv}balance", fact.concept.balance)
            if fact.isNumeric and not fact.isNil:
                fact.set(u"{http://www.xbrl.org/2003/ptv}decimals", unicode(inferredDecimals(fact)))
                fact.set(u"{http://www.xbrl.org/2003/ptv}precision", unicode(inferredPrecision(fact)))
            numFacts += 1
        except Exception, err:
            dts.error(u"saveInfoset.exception",
                     _(u"Facts exception %(fact)s %(value)s %(error)s."),
                     modelObject=fact, fact=fact.qname, value=fact.effectiveValue, error = err)
Example #5
0
def generateInstanceInfoset(dts, instanceInfosetFile):
    if dts.fileSource.isArchive:
        return
    import os, io
    from arelle import XmlUtil, XbrlConst
    from arelle.ValidateXbrlCalcs import inferredPrecision, inferredDecimals            
    
    XmlUtil.setXmlns(dts.modelDocument, "ptv", "http://www.xbrl.org/2003/ptv")
    
    numFacts = 0
    
    for fact in dts.facts:
        try:
            if fact.concept.periodType:
                fact.set("{http://www.xbrl.org/2003/ptv}periodType", fact.concept.periodType)
            if fact.concept.balance:
                fact.set("{http://www.xbrl.org/2003/ptv}balance", fact.concept.balance)
            if fact.isNumeric and not fact.isNil:
                fact.set("{http://www.xbrl.org/2003/ptv}decimals", str(inferredDecimals(fact)))
                fact.set("{http://www.xbrl.org/2003/ptv}precision", str(inferredPrecision(fact)))
            numFacts += 1
        except Exception as err:
            dts.error("saveInfoset.exception",
                     _("Facts exception %(fact)s %(value)s %(error)s."),
                     modelObject=fact, fact=fact.qname, value=fact.effectiveValue, error = err)

    fh = open(instanceInfosetFile, "w", encoding="utf-8")
    XmlUtil.writexml(fh, dts.modelDocument.xmlDocument, encoding="utf-8")
    fh.close()
    
    dts.info("info:saveInstanceInfoset",
             _("Instance infoset of %(entryFile)s has %(numberOfFacts)s facts in infoset file %(infosetOutputFile)s."),
             modelObject=dts,
             entryFile=dts.uri, numberOfFacts=numFacts, infosetOutputFile=instanceInfosetFile)
Example #6
0
 def isVEqualTo(self,
                other,
                deemP0Equal=False):  # facts may be in different instances
     if self.isTuple or other.isTuple:
         return False
     if self.isNil:
         return other.isNil
     if other.isNil:
         return False
     if not self.context.isEqualTo(other.context):
         return False
     if self.concept.isNumeric:
         if other.concept.isNumeric:
             if not self.unit.isEqualTo(other.unit):
                 return False
             if self.modelXbrl.modelManager.validateInferDecimals:
                 d = min((inferredDecimals(self), inferredDecimals(other)))
                 p = None
             else:
                 d = None
                 p = min(
                     (inferredPrecision(self), inferredPrecision(other)))
             if p == 0 and deemP0Equal:
                 return True
             return roundValue(self.value, precision=p,
                               decimals=d) == roundValue(other.value,
                                                         precision=p,
                                                         decimals=d)
         else:
             return False
     selfValue = self.value
     otherValue = other.value
     if isinstance(selfValue, str) and isinstance(otherValue, str):
         return selfValue.strip() == otherValue.strip()
     else:
         return selfValue == otherValue
Example #7
0
def infer_precision_decimals(xc, p, args, attrName):
    if len(args) != 1: raise XPathContext.FunctionNumArgs()
    if len(args[0]) != 1: raise XPathContext.FunctionArgType(1,"xbrl:item")
    modelItem = xc.modelItem(args[0][0])
    if modelItem: 
        modelConcept = modelItem.concept
        if modelConcept.isNumeric:
            if modelConcept.isFraction: return 'INF'
            from arelle.ValidateXbrlCalcs import (inferredDecimals,inferredPrecision)
            p = inferredPrecision(modelItem) if attrName == "precision" else inferredDecimals(modelItem)
            if isinf(p):
                return 'INF'
            if isnan(p):
                raise XPathContext.XPathException(p, 'xfie:ItemIsNotNumeric', _('Argument 1 {0} is not inferrable.').format(attrName))
            return p
    raise XPathContext.XPathException(p, 'xfie:ItemIsNotNumeric', _('Argument 1 is not reported with {0}.').format(attrName))
Example #8
0
def infer_precision_decimals(xc, p, args, attrName):
    if len(args) != 1: raise XPathContext.FunctionNumArgs()
    if len(args[0]) != 1: raise XPathContext.FunctionArgType(1, "xbrl:item")
    modelItem = xc.modelItem(args[0][0])
    if modelItem:
        modelConcept = modelItem.concept
        if modelConcept.isNumeric:
            if modelConcept.isFraction: return 'INF'
            from arelle.ValidateXbrlCalcs import (inferredDecimals,
                                                  inferredPrecision)
            p = inferredPrecision(
                modelItem) if attrName == "precision" else inferredDecimals(
                    modelItem)
            if isinf(p):
                return 'INF'
            if isnan(p):
                raise XPathContext.XPathException(
                    p, 'xfie:ItemIsNotNumeric',
                    _('Argument 1 {0} is not inferrable.').format(attrName))
            return p
    raise XPathContext.XPathException(
        p, 'xfie:ItemIsNotNumeric',
        _('Argument 1 is not reported with {0}.').format(attrName))
Example #9
0
def validate(val, modelXbrl, infosetModelXbrl):
    infoset = infosetModelXbrl.modelDocument
    if infoset.type == Type.INSTANCE:
        # compare facts (assumed out of order)
        infosetFacts = defaultdict(list)
        for fact in infosetModelXbrl.facts:
            infosetFacts[fact.qname].append(fact)
        if len(modelXbrl.factsInInstance) != len(
                infosetModelXbrl.factsInInstance):
            modelXbrl.error(
                "arelle:infosetTest",
                _("Fact counts mismatch, testcase instance %(foundFactCount)s, infoset instance %(expectedFactCount)s"
                  ),
                modelObject=(modelXbrl.modelDocument,
                             infosetModelXbrl.modelDocument),
                foundFactCount=len(modelXbrl.factsInInstance),
                expectedFactCount=len(infosetModelXbrl.factsInInstance))
        else:
            for i, instFact in enumerate(modelXbrl.facts):
                infosetFact = None
                for fact in infosetFacts[instFact.qname]:
                    if fact.isTuple and fact.isDuplicateOf(instFact,
                                                           deemP0Equal=True):
                        infosetFact = fact
                        break
                    elif fact.isItem and fact.isVEqualTo(instFact,
                                                         deemP0Equal=True):
                        infosetFact = fact
                        break
                if infosetFact is None:  # takes precision/decimals into account
                    if fact is not None:
                        fact.isVEqualTo(instFact, deemP0Equal=True)
                    modelXbrl.error(
                        "arelle:infosetTest",
                        _("Fact %(factNumber)s mismatch %(concept)s"),
                        modelObject=instFact,
                        factNumber=(i + 1),
                        concept=instFact.qname)
                else:
                    ptvPeriodType = infosetFact.get(
                        "{http://www.xbrl.org/2003/ptv}periodType")
                    ptvBalance = infosetFact.get(
                        "{http://www.xbrl.org/2003/ptv}balance")
                    ptvDecimals = infosetFact.get(
                        "{http://www.xbrl.org/2003/ptv}decimals")
                    ptvPrecision = infosetFact.get(
                        "{http://www.xbrl.org/2003/ptv}precision")
                    if ptvPeriodType and ptvPeriodType != instFact.concept.periodType:
                        modelXbrl.error(
                            "arelle:infosetTest",
                            _("Fact %(factNumber)s periodType mismatch %(concept)s expected %(expectedPeriodType)s found %(foundPeriodType)s"
                              ),
                            modelObject=(instFact, infosetFact),
                            factNumber=(i + 1),
                            concept=instFact.qname,
                            expectedPeriodType=ptvPeriodType,
                            foundPeriodType=instFact.concept.periodType)
                    if ptvBalance and ptvBalance != instFact.concept.balance:
                        modelXbrl.error(
                            "arelle:infosetTest",
                            _("Fact %(factNumber)s balance mismatch %(concept)s expected %(expectedBalance)s found %(foundBalance)s"
                              ),
                            modelObject=(instFact, infosetFact),
                            factNumber=(i + 1),
                            concept=instFact.qname,
                            expectedBalance=ptvBalance,
                            foundBalance=instFact.concept.balance)
                    if ptvDecimals and ptvDecimals != str(
                            inferredDecimals(fact)):
                        modelXbrl.error(
                            "arelle:infosetTest",
                            _("Fact %(factNumber)s inferred decimals mismatch %(concept)s expected %(expectedDecimals)s found %(inferredDecimals)s"
                              ),
                            modelObject=(instFact, infosetFact),
                            factNumber=(i + 1),
                            concept=instFact.qname,
                            expectedDecimals=ptvDecimals,
                            inferredDecimals=str(inferredDecimals(fact)))
                    if ptvPrecision and ptvPrecision != str(
                            inferredPrecision(fact)):
                        modelXbrl.error(
                            "arelle:infosetTest",
                            _("Fact %(factNumber)s inferred precision mismatch %(concept)s expected %(expectedPrecision)s found %(inferredPrecision)s"
                              ),
                            modelObject=(instFact, infosetFact),
                            factNumber=(i + 1),
                            concept=instFact.qname,
                            expectedPrecisions=ptvPrecision,
                            inferredPrecision=str(inferredPrecision(fact)))

    elif infoset.type == Type.ARCSINFOSET:
        # compare arcs
        for arcElt in XmlUtil.children(infoset.xmlRootElement,
                                       "http://www.xbrl.org/2003/ptv", "arc"):
            linkType = arcElt.get("linkType")
            arcRole = arcElt.get("arcRole")
            extRole = arcElt.get("extRole")
            fromObj = resolvePath(modelXbrl, arcElt.get("fromPath"))
            if fromObj is None:
                modelXbrl.error("arelle:infosetTest",
                                _("Arc fromPath not found: %(fromPath)s"),
                                modelObject=arcElt,
                                fromPath=arcElt.get("fromPath"))
                continue
            if linkType in ("label", "reference"):
                labelLang = arcElt.get("labelLang")
                resRole = arcElt.get("resRole")
                if linkType == "label":
                    expectedLabel = XmlUtil.text(arcElt)
                    foundLabel = fromObj.label(preferredLabel=resRole,
                                               fallbackToQname=False,
                                               lang=None,
                                               strip=True,
                                               linkrole=extRole)
                    if foundLabel != expectedLabel:
                        modelXbrl.error(
                            "arelle:infosetTest",
                            _("Label expected='%(expectedLabel)s', found='%(foundLabel)s'"
                              ),
                            modelObject=arcElt,
                            expectedLabel=expectedLabel,
                            foundLabel=foundLabel)
                    continue
                elif linkType == "reference":
                    expectedRef = XmlUtil.innerText(arcElt)
                    referenceFound = False
                    for refrel in modelXbrl.relationshipSet(
                            XbrlConst.conceptReference,
                            extRole).fromModelObject(fromObj):
                        ref = refrel.toModelObject
                        if resRole == ref.role:
                            foundRef = XmlUtil.innerText(ref)
                            if foundRef != expectedRef:
                                modelXbrl.error(
                                    "arelle:infosetTest",
                                    _("Reference inner text expected='%(expectedRef)s, found='%(foundRef)s'"
                                      ),
                                    modelObject=arcElt,
                                    expectedRef=expectedRef,
                                    foundRef=foundRef)
                            referenceFound = True
                            break
                    if referenceFound:
                        continue
                modelXbrl.error(
                    "arelle:infosetTest",
                    _("%(linkType)s not found containing '%(text)s' linkRole %(linkRole)s"
                      ),
                    modelObject=arcElt,
                    linkType=linkType.title(),
                    text=XmlUtil.innerText(arcElt),
                    linkRole=extRole)
            else:
                toObj = resolvePath(modelXbrl, arcElt.get("toPath"))
                if toObj is None:
                    modelXbrl.error("arelle:infosetTest",
                                    _("Arc toPath not found: %(toPath)s"),
                                    modelObject=arcElt,
                                    toPath=arcElt.get("toPath"))
                    continue
                weight = arcElt.get("weight")
                if weight is not None:
                    weight = float(weight)
                order = arcElt.get("order")
                if order is not None:
                    order = float(order)
                preferredLabel = arcElt.get("preferredLabel")
                found = False
                for rel in modelXbrl.relationshipSet(
                        arcRole, extRole).fromModelObject(fromObj):
                    if (rel.toModelObject == toObj
                            and (weight is None or rel.weight == weight)
                            and (order is None or rel.order == order)):
                        found = True
                if not found:
                    modelXbrl.error(
                        "arelle:infosetTest",
                        _("Arc not found: from %(fromPath)s, to %(toPath)s, role %(arcRole)s, linkRole $(extRole)s"
                          ),
                        modelObject=arcElt,
                        fromPath=arcElt.get("fromPath"),
                        toPath=arcElt.get("toPath"),
                        arcRole=arcRole,
                        linkRole=extRole)
                    continue
        # validate dimensions of each fact
        factElts = XmlUtil.children(modelXbrl.modelDocument.xmlRootElement,
                                    None, "*")
        for itemElt in XmlUtil.children(infoset.xmlRootElement, None, "item"):
            try:
                qnElt = XmlUtil.child(itemElt, None, "qnElement")
                factQname = qname(qnElt, XmlUtil.text(qnElt))
                sPointer = int(XmlUtil.child(itemElt, None, "sPointer").text)
                factElt = factElts[sPointer - 1]  # 1-based xpath indexing
                if factElt.qname != factQname:
                    modelXbrl.error(
                        "arelle:infosetTest",
                        _("Fact %(sPointer)s mismatch Qname, expected %(qnElt)s, observed %(factQname)s"
                          ),
                        modelObject=itemElt,
                        sPointer=sPointer,
                        qnElt=factQname,
                        factQname=factElt.qname)
                elif not factElt.isItem or factElt.context is None:
                    modelXbrl.error(
                        "arelle:infosetTest",
                        _("Fact %(sPointer)s has no context: %(qnElt)s"),
                        modelObject=(itemElt, factElt),
                        sPointer=sPointer,
                        qnElt=factQname)
                else:
                    context = factElt.context
                    memberElts = XmlUtil.children(itemElt, None, "member")
                    numNonDefaults = 0
                    for memberElt in memberElts:
                        dimElt = XmlUtil.child(memberElt, None, "qnDimension")
                        qnDim = qname(dimElt, XmlUtil.text(dimElt))
                        isDefault = XmlUtil.text(
                            XmlUtil.child(memberElt, None,
                                          "bDefaulted")) == "true"
                        if not isDefault:
                            numNonDefaults += 1
                        if not (
                            (qnDim in context.qnameDims and not isDefault) or
                            (qnDim in factElt.modelXbrl.qnameDimensionDefaults
                             and isDefault)):
                            modelXbrl.error(
                                "arelle:infosetTest",
                                _("Fact %(sPointer)s (qnElt)s dimension mismatch %(qnDim)s"
                                  ),
                                modelObject=(itemElt, factElt, context),
                                sPointer=sPointer,
                                qnElt=factQname,
                                qnDim=qnDim)
                    if numNonDefaults != len(context.qnameDims):
                        modelXbrl.error(
                            "arelle:infosetTest",
                            _("Fact %(sPointer)s (qnElt)s dimensions count mismatch"
                              ),
                            modelObject=(itemElt, factElt, context),
                            sPointer=sPointer,
                            qnElt=factQname)
            except (IndexError, ValueError, AttributeError) as err:
                modelXbrl.error(
                    "arelle:infosetTest",
                    _("Invalid entity fact dimensions infoset sPointer: %(test)s, error details: %(error)s"
                      ),
                    modelObject=itemElt,
                    test=XmlUtil.innerTextList(itemElt),
                    error=str(err))
Example #10
0
def _precision(node, sphinxContext, args):
    fact = factArg(node, sphinxContext, args, 0)
    return inferredPrecision(fact)
Example #11
0
def evaluate(xpCtx, varSet, derivedFact):
    # there may be multiple consis assertions parenting any formula
    for consisAsserRel in xpCtx.modelXbrl.relationshipSet(
            XbrlConst.consistencyAssertionFormula).toModelObject(varSet):
        consisAsser = consisAsserRel.fromModelObject
        hasProportionalAcceptanceRadius = consisAsser.hasProportionalAcceptanceRadius
        hasAbsoluteAcceptanceRadius = consisAsser.hasAbsoluteAcceptanceRadius
        if derivedFact is None:
            continue
        isNumeric = derivedFact.isNumeric
        if isNumeric and not derivedFact.isNil:
            derivedFactInferredPrecision = inferredPrecision(derivedFact)
            if derivedFactInferredPrecision == 0 and not hasProportionalAcceptanceRadius and not hasAbsoluteAcceptanceRadius:
                if xpCtx.formulaOptions.traceVariableSetExpressionResult:
                    xpCtx.modelXbrl.error(
                        _("Consistency assertion {0} formula {1} fact {2} has zero precision and no radius is defined, skipping consistency assertion"
                          ).format(consisAsser.id, varSet.xlinkLabel,
                                   derivedFact), "info", "formula:trace")
                continue

        # check xbrl validity of new fact

        # find source facts which match derived fact
        aspectMatchedInputFacts = []
        isStrict = consisAsser.isStrict
        for inputFact in xpCtx.modelXbrl.facts:
            if (not inputFact.isNil and inputFact.qname == derivedFact.qname
                    and inputFact.context.isEqualTo(
                        derivedFact.context,
                        dimensionalAspectModel=(varSet.aspectModel
                                                == "dimensional")) and
                (not isNumeric or inputFact.unit.isEqualTo(derivedFact.unit))):
                aspectMatchedInputFacts.append(inputFact)

        if len(aspectMatchedInputFacts) == 0:
            if isStrict:
                if derivedFact.isNil:
                    isSatisfied = True
                else:
                    isSatisfied = False
            else:
                if xpCtx.formulaOptions.traceVariableSetExpressionResult:
                    xpCtx.modelXbrl.error(
                        _("Consistency assertion {0} Formula {1} no input facts matched to {2}, skipping consistency assertion"
                          ).format(consisAsser.id, varSet.xlinkLabel,
                                   derivedFact), "info", "formula:trace")
                continue
        elif derivedFact.isNil:
            isSatisfied = False
        else:
            isSatisfied = True

        paramQnamesAdded = []
        for paramRel in consisAsser.orderedVariableRelationships:
            paramQname = paramRel.variableQname
            paramVar = paramRel.toModelObject
            paramValue = xpCtx.inScopeVars.get(paramVar.qname)
            paramAlreadyInVars = paramQname in xpCtx.inScopeVars
            if not paramAlreadyInVars:
                paramQnamesAdded.append(paramQname)
                xpCtx.inScopeVars[paramQname] = paramValue
        for fact in aspectMatchedInputFacts:
            if isSatisfied != True:
                break
            if fact.isNil:
                if not derivedFact.isNil:
                    isSatisfied = False
            elif isNumeric:
                factInferredPrecision = inferredPrecision(fact)
                if factInferredPrecision == 0 and not hasProportionalAcceptanceRadius and not hasAbsoluteAcceptanceRadius:
                    if xpCtx.formulaOptions.traceVariableSetExpressionResult:
                        xpCtx.modelXbrl.error(
                            _("Consistency assertion {0} Formula {1} input fact matched to {2} has zero precision and no radius, skipping consistency assertion"
                              ).format(consisAsser.id, varSet.xlinkLabel,
                                       derivedFact), "info", "formula:trace")
                        isSatisfied = None
                        break
                if hasProportionalAcceptanceRadius or hasAbsoluteAcceptanceRadius:
                    acceptance = consisAsser.evalRadius(
                        xpCtx, derivedFact.vEqValue)
                    if acceptance is not None:
                        if hasProportionalAcceptanceRadius:
                            acceptance *= derivedFact.vEqValue
                        isSatisfied = fabs(derivedFact.vEqValue -
                                           fact.vEqValue) <= fabs(acceptance)
                    else:
                        isSatisfied = None  # no radius
                else:
                    p = min(derivedFactInferredPrecision,
                            factInferredPrecision)
                    if (p == 0 or roundValue(derivedFact.vEqValue, precision=p)
                            != roundValue(fact.vEqValue, precision=p)):
                        isSatisfied = False
            else:
                if not xEqual(fact.concept,
                              fact.element,
                              derivedFact.element,
                              equalMode=S_EQUAL2):
                    isSatisfied = False
        for paramQname in paramQnamesAdded:
            xpCtx.inScopeVars.pop(paramQname)
        if isSatisfied is None:
            continue  # no evaluation
        if xpCtx.formulaOptions.traceVariableSetExpressionResult:
            xpCtx.modelXbrl.error(
                _("Consistency Assertion {0} result {1}").format(
                    consisAsser.id, isSatisfied), "info", "formula:trace")
        message = consisAsser.message(isSatisfied)
        if message:
            xpCtx.modelXbrl.error(message.evaluate(xpCtx), "info",
                                  "message:" + consisAsser.id)
        if isSatisfied: consisAsser.countSatisfied += 1
        else: consisAsser.countNotSatisfied += 1
Example #12
0
def evaluate(xpCtx, varSet, derivedFact):
    # there may be multiple consis assertions parenting any formula
    for consisAsserRel in xpCtx.modelXbrl.relationshipSet(XbrlConst.consistencyAssertionFormula).toModelObject(varSet):
        consisAsser = consisAsserRel.fromModelObject
        hasProportionalAcceptanceRadius = consisAsser.hasProportionalAcceptanceRadius
        hasAbsoluteAcceptanceRadius = consisAsser.hasAbsoluteAcceptanceRadius
        if derivedFact is None:
            continue
        isNumeric = derivedFact.isNumeric
        if isNumeric and not derivedFact.isNil:
            derivedFactInferredPrecision = inferredPrecision(derivedFact)
            if derivedFactInferredPrecision == 0 and not hasProportionalAcceptanceRadius and not hasAbsoluteAcceptanceRadius:
                if xpCtx.formulaOptions.traceVariableSetExpressionResult:
                    xpCtx.modelXbrl.error( _("Consistency assertion {0} formula {1} fact {2} has zero precision and no radius is defined, skipping consistency assertion").format(
                         consisAsser.id, varSet.xlinkLabel, derivedFact),
                        "info", "formula:trace")
                continue
    
        # check xbrl validity of new fact
        
        # find source facts which match derived fact
        aspectMatchedInputFacts = []
        isStrict = consisAsser.isStrict
        for inputFact in xpCtx.modelXbrl.facts:
            if (not inputFact.isNil and
                inputFact.qname == derivedFact.qname and
                inputFact.context.isEqualTo(derivedFact.context,
                                            dimensionalAspectModel=(varSet.aspectModel == "dimensional")) and
                (not isNumeric or inputFact.unit.isEqualTo(derivedFact.unit))):
                aspectMatchedInputFacts.append( inputFact )
        
        if len(aspectMatchedInputFacts) == 0:
            if isStrict:
                if derivedFact.isNil:
                    isSatisfied = True
                else:
                    isSatisfied = False
            else:
                if xpCtx.formulaOptions.traceVariableSetExpressionResult:
                    xpCtx.modelXbrl.error( _("Consistency assertion {0} Formula {1} no input facts matched to {2}, skipping consistency assertion").format( 
                        consisAsser.id, varSet.xlinkLabel, derivedFact),
                        "info", "formula:trace")
                continue
        elif derivedFact.isNil:
            isSatisfied = False
        else:
            isSatisfied = True
                
        paramQnamesAdded = []
        for paramRel in consisAsser.orderedVariableRelationships:
            paramQname = paramRel.variableQname
            paramVar = paramRel.toModelObject
            paramValue = xpCtx.inScopeVars.get(paramVar.qname)
            paramAlreadyInVars = paramQname in xpCtx.inScopeVars
            if not paramAlreadyInVars:
                paramQnamesAdded.append(paramQname)
                xpCtx.inScopeVars[paramQname] = paramValue
        for fact in aspectMatchedInputFacts:
            if isSatisfied != True: 
                break
            if fact.isNil:
                if not derivedFact.isNil:
                    isSatisfied = False
            elif isNumeric:
                factInferredPrecision = inferredPrecision(fact)
                if factInferredPrecision == 0 and not hasProportionalAcceptanceRadius and not hasAbsoluteAcceptanceRadius:
                    if xpCtx.formulaOptions.traceVariableSetExpressionResult:
                        xpCtx.modelXbrl.error( _("Consistency assertion {0} Formula {1} input fact matched to {2} has zero precision and no radius, skipping consistency assertion").format( 
                            consisAsser.id, varSet.xlinkLabel, derivedFact),
                            "info", "formula:trace")
                        isSatisfied = None
                        break
                if hasProportionalAcceptanceRadius or hasAbsoluteAcceptanceRadius:
                    acceptance = consisAsser.evalRadius(xpCtx, derivedFact.vEqValue)
                    if acceptance is not None:
                        if hasProportionalAcceptanceRadius:
                            acceptance *= derivedFact.vEqValue
                        isSatisfied = fabs(derivedFact.vEqValue - fact.vEqValue) <= fabs(acceptance)
                    else:
                        isSatisfied = None  # no radius
                else:
                    p = min(derivedFactInferredPrecision, factInferredPrecision)
                    if (p == 0 or
                        roundValue(derivedFact.vEqValue, precision=p) != roundValue(fact.vEqValue, precision=p)):
                        isSatisfied = False
            else:
                if not xEqual(fact.concept, fact.element, derivedFact.element, equalMode=S_EQUAL2):
                    isSatisfied = False
        for paramQname in paramQnamesAdded:
            xpCtx.inScopeVars.pop(paramQname)
        if isSatisfied is None:
            continue    # no evaluation
        if xpCtx.formulaOptions.traceVariableSetExpressionResult:
            xpCtx.modelXbrl.error( _("Consistency Assertion {0} result {1}").format( consisAsser.id, isSatisfied),
                "info", "formula:trace")
        message = consisAsser.message(isSatisfied)
        if message:
            xpCtx.modelXbrl.error(message.evaluate(xpCtx), "info", "message:" + consisAsser.id)
        if isSatisfied: consisAsser.countSatisfied += 1
        else: consisAsser.countNotSatisfied += 1
Example #13
0
def _precision(node, sphinxContext, args):
    fact = factArg(node, sphinxContext, args, 0)
    return inferredPrecision(fact)
Example #14
0
def validate(val, modelXbrl, infosetModelXbrl):
    infoset = infosetModelXbrl.modelDocument
    if infoset.type == Type.INSTANCE:
        # compare facts (assumed out of order)
        infosetFacts = defaultdict(list)
        for fact in infosetModelXbrl.facts:
            infosetFacts[fact.qname].append(fact)
        if len(modelXbrl.factsInInstance) != len(infosetModelXbrl.factsInInstance):
            modelXbrl.error("arelle:infosetTest",
                _("Fact counts mismatch, testcase instance %(foundFactCount)s, infoset instance %(expectedFactCount)s"),
                modelObject=(modelXbrl.modelDocument, infosetModelXbrl.modelDocument), 
                            foundFactCount=len(modelXbrl.factsInInstance),
                            expectedFactCount=len(infosetModelXbrl.factsInInstance))
        else:
            for i, instFact in enumerate(modelXbrl.facts):
                infosetFact = None
                for fact in infosetFacts[instFact.qname]:
                    if fact.isTuple and fact.isDuplicateOf(instFact, deemP0Equal=True):
                        infosetFact = fact
                        break
                    elif fact.isItem and fact.isVEqualTo(instFact, deemP0Equal=True):
                        infosetFact = fact
                        break
                if infosetFact is None: # takes precision/decimals into account
                    if fact is not None:
                        fact.isVEqualTo(instFact, deemP0Equal=True)
                    modelXbrl.error("arelle:infosetTest",
                        _("Fact %(factNumber)s mismatch %(concept)s"),
                        modelObject=instFact,
                                    factNumber=(i+1), 
                                    concept=instFact.qname)
                else:
                    ptvPeriodType = infosetFact.get("{http://www.xbrl.org/2003/ptv}periodType")
                    ptvBalance = infosetFact.get("{http://www.xbrl.org/2003/ptv}balance")
                    ptvDecimals = infosetFact.get("{http://www.xbrl.org/2003/ptv}decimals")
                    ptvPrecision = infosetFact.get("{http://www.xbrl.org/2003/ptv}precision")
                    if ptvPeriodType and ptvPeriodType != instFact.concept.periodType:
                        modelXbrl.error("arelle:infosetTest",
                            _("Fact %(factNumber)s periodType mismatch %(concept)s expected %(expectedPeriodType)s found %(foundPeriodType)s"),
                            modelObject=(instFact, infosetFact),
                                        factNumber=(i+1), 
                                        concept=instFact.qname,
                                        expectedPeriodType=ptvPeriodType,
                                        foundPeriodType=instFact.concept.periodType)
                    if ptvBalance and ptvBalance != instFact.concept.balance:
                        modelXbrl.error("arelle:infosetTest",
                            _("Fact %(factNumber)s balance mismatch %(concept)s expected %(expectedBalance)s found %(foundBalance)s"),
                            modelObject=(instFact, infosetFact),
                                        factNumber=(i+1), 
                                        concept=instFact.qname,
                                        expectedBalance=ptvBalance,
                                        foundBalance=instFact.concept.balance)
                    if ptvDecimals and ptvDecimals != str(inferredDecimals(fact)):
                        modelXbrl.error("arelle:infosetTest",
                            _("Fact %(factNumber)s inferred decimals mismatch %(concept)s expected %(expectedDecimals)s found %(inferredDecimals)s"),
                            modelObject=(instFact, infosetFact),
                                        factNumber=(i+1), 
                                        concept=instFact.qname,
                                        expectedDecimals=ptvDecimals,
                                        inferredDecimals=str(inferredDecimals(fact)))
                    if ptvPrecision and ptvPrecision != str(inferredPrecision(fact)):
                        modelXbrl.error("arelle:infosetTest",
                            _("Fact %(factNumber)s inferred precision mismatch %(concept)s expected %(expectedPrecision)s found %(inferredPrecision)s"),
                            modelObject=(instFact, infosetFact),
                                        factNumber=(i+1), 
                                        concept=instFact.qname,
                                        expectedPrecisions=ptvPrecision,
                                        inferredPrecision=str(inferredPrecision(fact)))
            
    elif infoset.type == Type.ARCSINFOSET:
        # compare arcs
        for arcElt in XmlUtil.children(infoset.xmlRootElement, "http://www.xbrl.org/2003/ptv", "arc"):
            linkType = arcElt.get("linkType")
            arcRole = arcElt.get("arcRole")
            extRole = arcElt.get("extRole")
            fromObj = resolvePath(modelXbrl, arcElt.get("fromPath"))
            if fromObj is None:
                modelXbrl.error("arelle:infosetTest",
                    _("Arc fromPath not found: %(fromPath)s"),
                    modelObject=arcElt, fromPath=arcElt.get("fromPath"))
                continue
            if linkType in ("label", "reference"):
                labelLang = arcElt.get("labelLang")
                resRole = arcElt.get("resRole")
                if linkType == "label":
                    expectedLabel = XmlUtil.text(arcElt)
                    foundLabel = fromObj.label(preferredLabel=resRole,fallbackToQname=False,lang=None,strip=True,linkrole=extRole)
                    if foundLabel != expectedLabel:
                        modelXbrl.error("arelle:infosetTest",
                            _("Label expected='%(expectedLabel)s', found='%(foundLabel)s'"),
                            modelObject=arcElt, expectedLabel=expectedLabel, foundLabel=foundLabel)
                    continue
                elif linkType == "reference":
                    expectedRef = XmlUtil.innerText(arcElt)
                    referenceFound = False
                    for refrel in modelXbrl.relationshipSet(XbrlConst.conceptReference,extRole).fromModelObject(fromObj):
                        ref = refrel.toModelObject
                        if resRole == ref.role:
                            foundRef = XmlUtil.innerText(ref)
                            if foundRef != expectedRef:
                                modelXbrl.error("arelle:infosetTest",
                                    _("Reference inner text expected='%(expectedRef)s, found='%(foundRef)s'"),
                                    modelObject=arcElt, expectedRef=expectedRef, foundRef=foundRef)
                            referenceFound = True
                            break
                    if referenceFound:
                        continue
                modelXbrl.error("arelle:infosetTest",
                    _("%(linkType)s not found containing '%(text)s' linkRole %(linkRole)s"),
                    modelObject=arcElt, linkType=linkType.title(), text=XmlUtil.innerText(arcElt), linkRole=extRole)
            else:
                toObj = resolvePath(modelXbrl, arcElt.get("toPath"))
                if toObj is None:
                    modelXbrl.error("arelle:infosetTest",
                        _("Arc toPath not found: %(toPath)s"),
                        modelObject=arcElt, toPath=arcElt.get("toPath"))
                    continue
                weight = arcElt.get("weight")
                if weight is not None:
                    weight = float(weight)
                order = arcElt.get("order")
                if order is not None:
                    order = float(order)
                preferredLabel = arcElt.get("preferredLabel")
                found = False
                for rel in modelXbrl.relationshipSet(arcRole, extRole).fromModelObject(fromObj):
                    if (rel.toModelObject == toObj and 
                        (weight is None or rel.weight == weight) and 
                        (order is None or rel.order == order)):
                        found = True
                if not found:
                    modelXbrl.error("arelle:infosetTest",
                        _("Arc not found: from %(fromPath)s, to %(toPath)s, role %(arcRole)s, linkRole $(extRole)s"),
                        modelObject=arcElt, fromPath=arcElt.get("fromPath"), toPath=arcElt.get("toPath"), arcRole=arcRole, linkRole=extRole)
                    continue
        # validate dimensions of each fact
        factElts = XmlUtil.children(modelXbrl.modelDocument.xmlRootElement, None, "*")
        for itemElt in XmlUtil.children(infoset.xmlRootElement, None, "item"):
            try:
                qnElt = XmlUtil.child(itemElt,None,"qnElement")
                factQname = qname(qnElt, XmlUtil.text(qnElt))
                sPointer = int(XmlUtil.child(itemElt,None,"sPointer").text)
                factElt = factElts[sPointer - 1] # 1-based xpath indexing
                if factElt.qname != factQname:
                    modelXbrl.error("arelle:infosetTest",
                        _("Fact %(sPointer)s mismatch Qname, expected %(qnElt)s, observed %(factQname)s"),
                        modelObject=itemElt, sPointer=sPointer, qnElt=factQname, factQname=factElt.qname)
                elif not factElt.isItem or factElt.context is None:
                    modelXbrl.error("arelle:infosetTest",
                        _("Fact %(sPointer)s has no context: %(qnElt)s"),
                        modelObject=(itemElt,factElt), sPointer=sPointer, qnElt=factQname)
                else:
                    context = factElt.context
                    memberElts = XmlUtil.children(itemElt,None,"member")
                    numNonDefaults = 0
                    for memberElt in memberElts:
                        dimElt = XmlUtil.child(memberElt, None, "qnDimension")
                        qnDim = qname(dimElt, XmlUtil.text(dimElt))
                        isDefault = XmlUtil.text(XmlUtil.child(memberElt, None, "bDefaulted")) == "true"
                        if not isDefault:
                            numNonDefaults += 1
                        if not ((qnDim in context.qnameDims and not isDefault) or
                                (qnDim in factElt.modelXbrl.qnameDimensionDefaults and isDefault)):
                            modelXbrl.error("arelle:infosetTest",
                                _("Fact %(sPointer)s (qnElt)s dimension mismatch %(qnDim)s"),
                                modelObject=(itemElt, factElt, context), sPointer=sPointer, qnElt=factQname, qnDim=qnDim)
                    if numNonDefaults != len(context.qnameDims):
                        modelXbrl.error("arelle:infosetTest",
                            _("Fact %(sPointer)s (qnElt)s dimensions count mismatch"),
                            modelObject=(itemElt, factElt, context), sPointer=sPointer, qnElt=factQname)
            except (IndexError, ValueError, AttributeError) as err:
                modelXbrl.error("arelle:infosetTest",
                    _("Invalid entity fact dimensions infoset sPointer: %(test)s, error details: %(error)s"),
                    modelObject=itemElt, test=XmlUtil.innerTextList(itemElt), error=str(err))
def evaluate(xpCtx, varSet, derivedFact):
    # there may be multiple consis assertions parenting any formula
    for consisAsserRel in xpCtx.modelXbrl.relationshipSet(XbrlConst.consistencyAssertionFormula).toModelObject(varSet):
        consisAsser = consisAsserRel.fromModelObject
        hasProportionalAcceptanceRadius = consisAsser.hasProportionalAcceptanceRadius
        hasAbsoluteAcceptanceRadius = consisAsser.hasAbsoluteAcceptanceRadius
        if derivedFact is None:
            continue
        isNumeric = derivedFact.isNumeric
        if isNumeric and not derivedFact.isNil:
            derivedFactInferredPrecision = inferredPrecision(derivedFact)
            if derivedFactInferredPrecision == 0 and not hasProportionalAcceptanceRadius and not hasAbsoluteAcceptanceRadius:
                if xpCtx.formulaOptions.traceVariableSetExpressionResult:
                    xpCtx.modelXbrl.info(u"formula:trace",
                         _(u"Consistency assertion %(id)s formula %(xlinkLabel)s fact %(derivedFact)s has zero precision and no radius is defined, skipping consistency assertion"),
                         modelObject=consisAsser, id=consisAsser.id, xlinkLabel=varSet.xlinkLabel, derivedFact=derivedFact)
                continue
    
        # check xbrl validity of new fact
        
        # find source facts which match derived fact
        aspectMatchedInputFacts = []
        isStrict = consisAsser.isStrict
        for inputFact in xpCtx.modelXbrl.facts:
            if (not inputFact.isNil and
                inputFact.qname == derivedFact.qname and
                inputFact.context.isEqualTo(derivedFact.context,
                                            dimensionalAspectModel=(varSet.aspectModel == u"dimensional")) and
                (not isNumeric or inputFact.unit.isEqualTo(derivedFact.unit))):
                aspectMatchedInputFacts.append( inputFact )
        
        if len(aspectMatchedInputFacts) == 0:
            if isStrict:
                if derivedFact.isNil:
                    isSatisfied = True
                else:
                    isSatisfied = False
            else:
                if xpCtx.formulaOptions.traceVariableSetExpressionResult:
                    xpCtx.modelXbrl.info(u"formula:trace",
                         _(u"Consistency assertion %(id)s formula %(xlinkLabel)s no input facts matched to %(derivedFact)s, skipping consistency assertion"),
                         modelObject=consisAsser, id=consisAsser.id, xlinkLabel=varSet.xlinkLabel, derivedFact=derivedFact)
                continue
        elif derivedFact.isNil:
            isSatisfied = False
        else:
            isSatisfied = True
                
        paramQnamesAdded = []
        for paramRel in consisAsser.orderedVariableRelationships:
            paramQname = paramRel.variableQname
            paramVar = paramRel.toModelObject
            paramValue = xpCtx.inScopeVars.get(paramVar.parameterQname)
            paramAlreadyInVars = paramQname in xpCtx.inScopeVars
            if not paramAlreadyInVars:
                paramQnamesAdded.append(paramQname)
                xpCtx.inScopeVars[paramQname] = paramValue
        acceptance = None
        for fact in aspectMatchedInputFacts:
            if isSatisfied != True: 
                break
            if fact.isNil:
                if not derivedFact.isNil:
                    isSatisfied = False
            elif isNumeric:
                factInferredPrecision = inferredPrecision(fact)
                if factInferredPrecision == 0 and not hasProportionalAcceptanceRadius and not hasAbsoluteAcceptanceRadius:
                    if xpCtx.formulaOptions.traceVariableSetExpressionResult:
                        xpCtx.modelXbrl.info(u"formula:trace",
                             _(u"Consistency assertion %(id)s formula %(xlinkLabel)s input fact matched to %(derivedFact)s has zero precision and no radius, skipping consistency assertion"),
                             modelObject=consisAsser, id=consisAsser.id, xlinkLabel=varSet.xlinkLabel, derivedFact=derivedFact)
                        isSatisfied = None
                        break
                if hasProportionalAcceptanceRadius or hasAbsoluteAcceptanceRadius:
                    acceptance = consisAsser.evalRadius(xpCtx, derivedFact.vEqValue)
                    if acceptance is not None:
                        if hasProportionalAcceptanceRadius:
                            acceptance *= derivedFact.vEqValue
                        isSatisfied = fabs(derivedFact.vEqValue - fact.vEqValue) <= fabs(acceptance)
                    else:
                        isSatisfied = None  # no radius
                else:
                    p = min(derivedFactInferredPrecision, factInferredPrecision)
                    if (p == 0 or
                        roundValue(derivedFact.value, precision=p) != roundValue(fact.value, precision=p)):
                        isSatisfied = False
            else:
                if not xEqual(fact, derivedFact, equalMode=S_EQUAL2):
                    isSatisfied = False
        if isSatisfied is not None:  # None means no evaluation
            if xpCtx.formulaOptions.traceVariableSetExpressionResult:
                xpCtx.modelXbrl.info(u"formula:trace",
                     _(u"Consistency assertion %(id)s result %(result)s"),
                     modelObject=consisAsser, id=consisAsser.id, result=isSatisfied)
            message = consisAsser.message(isSatisfied)
            if message is not None:
                xpCtx.inScopeVars[XbrlConst.qnCaAspectMatchedFacts] = aspectMatchedInputFacts
                xpCtx.inScopeVars[XbrlConst.qnCaAcceptanceRadius] = acceptance
                xpCtx.inScopeVars[XbrlConst.qnCaAbsoluteAcceptanceRadiusExpression] = consisAsser.get(u"absoluteAcceptanceRadius")
                xpCtx.inScopeVars[XbrlConst.qnCaProportionalAcceptanceRadiusExpression] = consisAsser.get(u"proportionalAcceptanceRadius")
                xpCtx.modelXbrl.info(u"message:" + consisAsser.id, message.evaluate(xpCtx),
                                     modelObject=message,
                                     messageCodes=(u"message:{variableSetID|xlinkLabel}"))
                xpCtx.inScopeVars.pop(XbrlConst.qnCaAspectMatchedFacts)
                xpCtx.inScopeVars.pop(XbrlConst.qnCaAcceptanceRadius)
                xpCtx.inScopeVars.pop(XbrlConst.qnCaAbsoluteAcceptanceRadiusExpression)
                xpCtx.inScopeVars.pop(XbrlConst.qnCaProportionalAcceptanceRadiusExpression)
            if isSatisfied: consisAsser.countSatisfied += 1
            else: consisAsser.countNotSatisfied += 1
        for paramQname in paramQnamesAdded:
            xpCtx.inScopeVars.pop(paramQname)