Exemple #1
0
def checkFormulaRules(val, formula, nameVariables):
    from arelle.ModelFormulaObject import (Aspect)
    if not (formula.hasRule(Aspect.CONCEPT) or formula.source(Aspect.CONCEPT)):
        if XmlUtil.hasDescendant(formula.element, XbrlConst.formula,
                                 "concept"):
            val.modelXbrl.error(
                _("Formula {0} concept rule does not have a nearest source and does not have a child element"
                  ).format(formula.xlinkLabel), "err",
                "xbrlfe:incompleteConceptRule")
        else:
            val.modelXbrl.error(
                _("Formula {0} omits a rule for the concept aspect").format(
                    formula.xlinkLabel), "err", "xbrlfe:missingConceptRule")
    if (not (formula.hasRule(Aspect.SCHEME) or formula.source(Aspect.SCHEME))
            or not (formula.hasRule(Aspect.VALUE)
                    or formula.source(Aspect.VALUE))):
        if XmlUtil.hasDescendant(formula.element, XbrlConst.formula,
                                 "entityIdentifier"):
            val.modelXbrl.error(
                _("Formula {0} entity identifier rule does not have a nearest source and does not have either a @scheme or a @value attribute"
                  ).format(formula.xlinkLabel), "err",
                "xbrlfe:incompleteEntityIdentifierRule")
        else:
            val.modelXbrl.error(
                _("Formula {0} omits a rule for the entity identifier aspect"
                  ).format(formula.xlinkLabel), "err",
                "xbrlfe:missingEntityIdentifierRule")
    if not (formula.hasRule(Aspect.PERIOD_TYPE)
            or formula.source(Aspect.PERIOD_TYPE)):
        if XmlUtil.hasDescendant(formula.element, XbrlConst.formula, "period"):
            val.modelXbrl.error(
                _("Formula {0} period rule does not have a nearest source and does not have a child element"
                  ).format(formula.xlinkLabel), "err",
                "xbrlfe:incompletePeriodRule")
        else:
            val.modelXbrl.error(
                _("Formula {0} omits a rule for the period aspect").format(
                    formula.xlinkLabel), "err", "xbrlfe:missingPeriodRule")
    # for unit need to see if the qname is statically determinable to determine if numeric
    concept = val.modelXbrl.qnameConcepts.get(
        formula.evaluateRule(None, Aspect.CONCEPT))
    if not concept:  # is there a source with a static QName filter
        sourceFactVar = nameVariables.get(formula.source(Aspect.CONCEPT))
        if isinstance(sourceFactVar, ModelFactVariable):
            for varFilterRels in (formula.groupFilterRelationships,
                                  sourceFactVar.filterRelationships):
                for varFilterRel in varFilterRels:
                    filter = varFilterRel.toModelObject
                    if isinstance(
                            filter, ModelConceptName
                    ):  # relationship not constrained to real filters
                        for conceptQname in filter.conceptQnames:
                            concept = val.modelXbrl.qnameConcepts.get(
                                conceptQname)
                            if concept and concept.isNumeric:
                                break
    if concept:  # from concept aspect rule or from source factVariable concept Qname filter
        if concept.isNumeric:
            if not (formula.hasRule(Aspect.MULTIPLY_BY) or formula.hasRule(
                    Aspect.DIVIDE_BY) or formula.source(Aspect.UNIT)):
                if XmlUtil.hasDescendant(formula.element, XbrlConst.formula,
                                         "unit"):
                    val.modelXbrl.error(
                        _("Formula {0} unit rule does not have a source and does not have a child element"
                          ).format(formula.xlinkLabel), "err",
                        "xbrlfe:missingSAVForUnitRule")
                else:
                    val.modelXbrl.error(
                        _("Formula {0} omits a rule for the unit aspect"
                          ).format(formula.xlinkLabel), "err",
                        "xbrlfe:missingUnitRule")
        elif (formula.hasRule(Aspect.MULTIPLY_BY)
              or formula.hasRule(Aspect.DIVIDE_BY)
              or formula.source(Aspect.UNIT, acceptFormulaSource=False)):
            val.modelXbrl.error(
                _("Formula {0} has a rule for the unit aspect of a non-numeric concept {1}"
                  ).format(formula.xlinkLabel, str(concept.qname)), "err",
                "xbrlfe:conflictingAspectRules")
        aspectPeriodType = formula.evaluateRule(None, Aspect.PERIOD_TYPE)
        if ((concept.periodType == "duration"
             and aspectPeriodType == "instant")
                or (concept.periodType == "instant"
                    and aspectPeriodType in ("duration", "forever"))):
            val.modelXbrl.error(
                _("Formula {0} has a rule for the {2} period aspect of a {3} concept {1}"
                  ).format(formula.xlinkLabel, str(concept.qname),
                           aspectPeriodType, concept.periodType), "err",
                "xbrlfe:conflictingAspectRules")

    # check dimension elements
    for eltName, dim, badUsageErr, missingSavErr in (
        ("explicitDimension", "explicit",
         "xbrlfe:badUsageOfExplicitDimensionRule",
         "xbrlfe:missingSAVForExplicitDimensionRule"),
        ("typedDimension", "typed", "xbrlfe:badUsageOfTypedDimensionRule",
         "xbrlfe:missingSAVForTypedDimensionRule")):
        for dimElt in XmlUtil.descendants(formula.element, XbrlConst.formula,
                                          eltName):
            dimQname = qname(dimElt, dimElt.getAttribute("dimension"))
            dimConcept = val.modelXbrl.qnameConcepts.get(dimQname)
            if dimQname and (
                    not dimConcept or
                (not dimConcept.isExplicitDimension
                 if dim == "explicit" else not dimConcept.isTypedDimension)):
                val.modelXbrl.error(
                    _("Formula {0} dimension attribute {1} on the {2} dimension rule contains a QName that does not identify an {2} dimension."
                      ).format(formula.xlinkLabel, dimQname, dim), "err",
                    badUsageErr)
            elif not XmlUtil.hasChild(dimElt, XbrlConst.formula,
                                      "*") and not formula.source(
                                          Aspect.DIMENSIONS, dimElt):
                val.modelXbrl.error(
                    _("Formula {0} {1} dimension rule does not have any child elements and does not have a SAV for the {2} dimension that is identified by its dimension attribute."
                      ).format(formula.xlinkLabel, dim, dimQname), "err",
                    missingSavErr)

    # check aspect model expectations
    if formula.aspectModel == "non-dimensional":
        unexpectedElts = XmlUtil.descendants(
            formula.element, XbrlConst.formula,
            ("explicitDimension", "typedDimension"))
        if unexpectedElts:
            val.modelXbrl.error(
                _("Formula {0} aspect model, {1}, includes an rule for aspect not defined in this aspect model: {2}"
                  ).format(
                      formula.xlinkLabel, formula.aspectModel,
                      ", ".join([elt.localName for elt in unexpectedElts])),
                "err", "xbrlfe:unrecognisedAspectRule")

    # check source qnames
    for sourceElt in ([formula.element] + XmlUtil.descendants(
            formula.element, XbrlConst.formula, "*", "source", "*")):
        if sourceElt.hasAttribute("source"):
            qnSource = qname(sourceElt,
                             sourceElt.getAttribute("source"),
                             noPrefixIsNoNamespace=True)
            if qnSource == XbrlConst.qnFormulaUncovered:
                if formula.implicitFiltering != "true":
                    val.modelXbrl.error(
                        _("Formula {0}, not implicit filtering element has formulaUncovered source: {1}"
                          ).format(formula.xlinkLabel, sourceElt.localName),
                        "err", "xbrlfe:illegalUseOfUncoveredQName")
            elif qnSource not in nameVariables:
                val.modelXbrl.error(
                    _("Variable set {0}, source {1} is not in the variable set"
                      ).format(formula.xlinkLabel, qnSource), "err",
                    "xbrlfe:nonexistentSourceVariable")
            else:
                factVariable = nameVariables.get(qnSource)
                if not isinstance(factVariable, ModelFactVariable):
                    val.modelXbrl.error(
                        _("Variable set {0}, source {1} not a factVariable but is a {2}"
                          ).format(formula.xlinkLabel, qnSource,
                                   factVariable.localName), "err",
                        "xbrlfe:nonexistentSourceVariable")
                elif factVariable.fallbackValue is not None:
                    val.modelXbrl.error(
                        _("Formula {0}: source {1} is a fact variable that has a fallback value"
                          ).format(formula.xlinkLabel, str(qnSource)), "err",
                        "xbrlfe:bindEmptySourceVariable")
                elif sourceElt.localName == "formula" and factVariable.bindAsSequence == "true":
                    val.modelXbrl.error(
                        _("Formula {0}: formula source {1} is a fact variable that binds as a sequence"
                          ).format(formula.xlinkLabel, str(qnSource)), "err",
                        "xbrlfe:defaultAspectValueConflicts")
Exemple #2
0
def checkFormulaRules(val, formula, nameVariables):
    from arelle.ModelFormulaObject import (Aspect)
    if not (formula.hasRule(Aspect.CONCEPT) or formula.source(Aspect.CONCEPT)):
        if XmlUtil.hasDescendant(formula.element, XbrlConst.formula, "concept"):
            val.modelXbrl.error(_("Formula {0} concept rule does not have a nearest source and does not have a child element").format(formula.xlinkLabel),
                                "err", "xbrlfe:incompleteConceptRule") 
        else:
            val.modelXbrl.error(_("Formula {0} omits a rule for the concept aspect").format(formula.xlinkLabel),
                                "err", "xbrlfe:missingConceptRule") 
    if (not (formula.hasRule(Aspect.SCHEME) or formula.source(Aspect.SCHEME)) or
        not (formula.hasRule(Aspect.VALUE) or formula.source(Aspect.VALUE))):
        if XmlUtil.hasDescendant(formula.element, XbrlConst.formula, "entityIdentifier"):
            val.modelXbrl.error(_("Formula {0} entity identifier rule does not have a nearest source and does not have either a @scheme or a @value attribute").format(formula.xlinkLabel),
                                "err", "xbrlfe:incompleteEntityIdentifierRule") 
        else:
            val.modelXbrl.error(_("Formula {0} omits a rule for the entity identifier aspect").format(formula.xlinkLabel),
                                "err", "xbrlfe:missingEntityIdentifierRule") 
    if not (formula.hasRule(Aspect.PERIOD_TYPE) or formula.source(Aspect.PERIOD_TYPE)):
        if XmlUtil.hasDescendant(formula.element, XbrlConst.formula, "period"):
            val.modelXbrl.error(_("Formula {0} period rule does not have a nearest source and does not have a child element").format(formula.xlinkLabel),
                                "err", "xbrlfe:incompletePeriodRule") 
        else:
            val.modelXbrl.error(_("Formula {0} omits a rule for the period aspect").format(formula.xlinkLabel),
                                "err", "xbrlfe:missingPeriodRule") 
    # for unit need to see if the qname is statically determinable to determine if numeric
    concept = val.modelXbrl.qnameConcepts.get(formula.evaluateRule(None, Aspect.CONCEPT))
    if not concept: # is there a source with a static QName filter
        sourceFactVar = nameVariables.get(formula.source(Aspect.CONCEPT))
        if isinstance(sourceFactVar, ModelFactVariable):
            for varFilterRels in (formula.groupFilterRelationships, sourceFactVar.filterRelationships):
                for varFilterRel in varFilterRels:
                    filter = varFilterRel.toModelObject
                    if isinstance(filter,ModelConceptName):  # relationship not constrained to real filters
                        for conceptQname in filter.conceptQnames:
                            concept = val.modelXbrl.qnameConcepts.get(conceptQname)
                            if concept and concept.isNumeric:
                                break
    if concept: # from concept aspect rule or from source factVariable concept Qname filter
        if concept.isNumeric:
            if not (formula.hasRule(Aspect.MULTIPLY_BY) or formula.hasRule(Aspect.DIVIDE_BY) or formula.source(Aspect.UNIT)):
                if XmlUtil.hasDescendant(formula.element, XbrlConst.formula, "unit"):
                    val.modelXbrl.error(_("Formula {0} unit rule does not have a source and does not have a child element").format(formula.xlinkLabel),
                                        "err", "xbrlfe:missingSAVForUnitRule") 
                else:
                    val.modelXbrl.error(_("Formula {0} omits a rule for the unit aspect").format(formula.xlinkLabel),
                                        "err", "xbrlfe:missingUnitRule") 
        elif (formula.hasRule(Aspect.MULTIPLY_BY) or formula.hasRule(Aspect.DIVIDE_BY) or 
              formula.source(Aspect.UNIT, acceptFormulaSource=False)):
            val.modelXbrl.error(_("Formula {0} has a rule for the unit aspect of a non-numeric concept {1}").format(formula.xlinkLabel, str(concept.qname)),
                                "err", "xbrlfe:conflictingAspectRules") 
        aspectPeriodType = formula.evaluateRule(None, Aspect.PERIOD_TYPE)
        if ((concept.periodType == "duration" and aspectPeriodType == "instant") or
            (concept.periodType == "instant" and aspectPeriodType in ("duration","forever"))):
            val.modelXbrl.error(_("Formula {0} has a rule for the {2} period aspect of a {3} concept {1}").format(formula.xlinkLabel, str(concept.qname), aspectPeriodType, concept.periodType),
                                "err", "xbrlfe:conflictingAspectRules") 
    
    # check dimension elements
    for eltName, dim, badUsageErr, missingSavErr in (("explicitDimension", "explicit", "xbrlfe:badUsageOfExplicitDimensionRule", "xbrlfe:missingSAVForExplicitDimensionRule"),
                                                     ("typedDimension", "typed", "xbrlfe:badUsageOfTypedDimensionRule", "xbrlfe:missingSAVForTypedDimensionRule")):
        for dimElt in XmlUtil.descendants(formula.element, XbrlConst.formula, eltName):
            dimQname = qname(dimElt, dimElt.getAttribute("dimension"))
            dimConcept = val.modelXbrl.qnameConcepts.get(dimQname)
            if dimQname and (not dimConcept or (not dimConcept.isExplicitDimension if dim == "explicit" else not dimConcept.isTypedDimension)):
                val.modelXbrl.error(_("Formula {0} dimension attribute {1} on the {2} dimension rule contains a QName that does not identify an {2} dimension.").format(formula.xlinkLabel, dimQname, dim),
                                    "err", badUsageErr) 
            elif not XmlUtil.hasChild(dimElt, XbrlConst.formula, "*") and not formula.source(Aspect.DIMENSIONS, dimElt):
                val.modelXbrl.error(_("Formula {0} {1} dimension rule does not have any child elements and does not have a SAV for the {2} dimension that is identified by its dimension attribute.").format(formula.xlinkLabel, dim, dimQname),
                                    "err", missingSavErr) 
    
    # check aspect model expectations
    if formula.aspectModel == "non-dimensional":
        unexpectedElts = XmlUtil.descendants(formula.element, XbrlConst.formula, ("explicitDimension", "typedDimension"))
        if unexpectedElts:
            val.modelXbrl.error(_("Formula {0} aspect model, {1}, includes an rule for aspect not defined in this aspect model: {2}").format(
                                formula.xlinkLabel, formula.aspectModel, ", ".join([elt.localName for elt in unexpectedElts])),
                                "err", "xbrlfe:unrecognisedAspectRule") 

    # check source qnames
    for sourceElt in ([formula.element] + 
                     XmlUtil.descendants(formula.element, XbrlConst.formula, "*", "source","*")):
        if sourceElt.hasAttribute("source"):
            qnSource = qname(sourceElt, sourceElt.getAttribute("source"), noPrefixIsNoNamespace=True)
            if qnSource == XbrlConst.qnFormulaUncovered:
                if formula.implicitFiltering != "true":
                    val.modelXbrl.error(_("Formula {0}, not implicit filtering element has formulaUncovered source: {1}").format(
                                  formula.xlinkLabel, sourceElt.localName), "err", "xbrlfe:illegalUseOfUncoveredQName") 
            elif qnSource not in nameVariables:
                val.modelXbrl.error(_("Variable set {0}, source {1} is not in the variable set").format(
                              formula.xlinkLabel, qnSource), "err", "xbrlfe:nonexistentSourceVariable")
            else:
                factVariable = nameVariables.get(qnSource)
                if not isinstance(factVariable, ModelFactVariable):
                    val.modelXbrl.error(_("Variable set {0}, source {1} not a factVariable but is a {2}").format(
                                  formula.xlinkLabel, qnSource, factVariable.localName), "err", "xbrlfe:nonexistentSourceVariable")
                elif factVariable.fallbackValue is not None:
                    val.modelXbrl.error(_("Formula {0}: source {1} is a fact variable that has a fallback value").format(formula.xlinkLabel, str(qnSource)),
                                        "err", "xbrlfe:bindEmptySourceVariable")
                elif sourceElt.localName == "formula" and factVariable.bindAsSequence == "true":
                    val.modelXbrl.error(_("Formula {0}: formula source {1} is a fact variable that binds as a sequence").format(formula.xlinkLabel, str(qnSource)),
                                        "err", "xbrlfe:defaultAspectValueConflicts")