Esempio n. 1
0
def dqc_0004_16(instance,error_log,suppress_errors,namespaces):
    """DQC_0004 Element Values Are Equal"""

    concept_Assets = instance.dts.resolve_concept(xml.QName('Assets',namespaces.get('us-gaap')))
    concept_LiabilitiesAndStockholdersEquity = instance.dts.resolve_concept(xml.QName('LiabilitiesAndStockholdersEquity',namespaces.get('us-gaap')))
    if concept_Assets and concept_LiabilitiesAndStockholdersEquity:
        _dqc_0004(instance,error_log,suppress_errors,'DQC.US.0004.16',concept_Assets,concept_LiabilitiesAndStockholdersEquity)
Esempio n. 2
0
def dqc_0011(instance,error_log,suppress_errors,namespaces):
    """DQC_0011 Dimensional Equivalents """

    for rule_id, lineItemPrefix, lineItemName, dimItemPrefix, dimItemName, axisPrefix, axisName, memberPrefix, memberName, weight in dqc_0011_facts:
        lineConcept = instance.dts.resolve_concept(xml.QName(lineItemName, namespaces.get(lineItemPrefix)))
        dimConcept = instance.dts.resolve_concept(xml.QName(dimItemName,namespaces.get(dimItemPrefix)))
        axisConcept = instance.dts.resolve_concept(xml.QName(axisName,namespaces.get(axisPrefix)))
        memberConcept = instance.dts.resolve_concept(xml.QName(memberName,namespaces.get(memberPrefix)))
        # select all facts with name lineItemName and no value for explicit dimension axisName
        lineItemConstraintSet = xbrl.ConstraintSet()
        lineItemConstraintSet.add(xbrl.ConceptAspectValue(lineConcept))
        lineItemConstraintSet.add(xbrl.ExplicitDimensionAspectValue(axisConcept))
        lineFacts = instance.facts.filter(lineItemConstraintSet)
        for lineFact in lineFacts:
            if not isinstance(lineFact, xbrl.Item) or lineFact.xsi_nil:
                continue
            # select all facts with name dimItemName and explicit dimension axisName=memberName and all other aspect values equal to their respective value of lineFact
            dimItemConstraintSet = lineFact.aspect_values
            dimItemConstraintSet.add(xbrl.ConceptAspectValue(dimConcept))
            dimItemConstraintSet.add(xbrl.ExplicitDimensionAspectValue(axisConcept, memberConcept))
            dimFacts = instance.facts.filter(dimItemConstraintSet)
            lineValue = lineFact.effective_numeric_value
            for dimFact in dimFacts:
                if not isinstance(dimFact, xbrl.Item) or dimFact.xsi_nil:
                    continue
                dimValue = dimFact.effective_numeric_value
                if dimValue * weight != lineValue:
                    report_error(error_log,suppress_errors,rule_id,fact1=lineFact,fact2=dimFact,weight=weight)
Esempio n. 3
0
def dqc_0005_49(instance,error_log,suppress_errors,namespaces,reporting_period_ends):
    """DQC_0005.49 Subsequent events"""

    dim_StatementScenarioAxis = instance.dts.resolve_concept(xml.QName('StatementScenarioAxis',namespaces.get('us-gaap')))
    if dim_StatementScenarioAxis:
        member_ScenarioForecastMember = instance.dts.resolve_concept(xml.QName('ScenarioForecastMember',namespaces.get('us-gaap')))

        cs = xbrl.ConstraintSet()
        cs[dim_StatementScenarioAxis] = member_ScenarioForecastMember
        facts = instance.facts.filter(cs)
        _dqc_0005(instance,error_log,suppress_errors,'DQC.US.0005.49',namespaces,facts,reporting_period_ends,operator.gt,{'us-gaap:StatementScenarioAxis':dim_StatementScenarioAxis,'us-gaap:ScenarioForecastMember':member_ScenarioForecastMember})
Esempio n. 4
0
def _dqc_0005(instance,error_log,suppress_errors,rule_id,namespaces,facts,reporting_period_ends,cmp,additional_params={}):
    dim_LegalEntityAxis = instance.dts.resolve_concept(xml.QName('LegalEntityAxis',namespaces['dei']))
    concept_EntityCommonStockSharesOutstanding = instance.dts.resolve_concept(xml.QName('EntityCommonStockSharesOutstanding',namespaces['dei']))
    for fact1 in facts:

        reporting_period_end = reporting_period_ends.get(dimension_value(fact1,dim_LegalEntityAxis))
        if not reporting_period_end:
            reporting_period_end = reporting_period_ends.get(dim_LegalEntityAxis.default_member)

        if reporting_period_end and not cmp(period_end(fact1),reporting_period_end[1]):
            params = {'fact1':fact1,'dei:DocumentPeriodEndDate':reporting_period_end[0]}
            params.update(additional_params)
            report_error(error_log,suppress_errors,rule_id,**params)
Esempio n. 5
0
def dqc_0009(instance,error_log,suppress_errors,namespaces):
    """DQC_0009 Element A must be less than or equal to Element B"""

    for rule_id, prefix1, name1, prefix2, name2 in dqc_0009_facts:
        concept1 = instance.dts.resolve_concept(xml.QName(name1,namespaces.get(prefix1)))
        concept2 = instance.dts.resolve_concept(xml.QName(name2,namespaces.get(prefix2)))
        if concept1 and concept2:
            for fact1 in instance.facts.filter(concept1,allow_nil=False):
                # All comparisons between fact values occur between facts of equivalent dimensions.  A rule will produce a message for each occurrence of the compared facts in equivalent dimensions.
                cs = xbrl.ConstraintSet(fact1)
                cs[xbrl.Aspect.CONCEPT] = concept2
                for fact2 in instance.facts.filter(cs,allow_nil=False,allow_additional_dimensions=False):
                    if not decimal_comparison(fact1,fact2,less_or_equal):
                        report_error(error_log,suppress_errors,rule_id,fact1=fact1,fact2=fact2)
Esempio n. 6
0
def dqc_0005_17(instance,error_log,suppress_errors,namespaces,reporting_period_ends):
    """DQC_0005.17 Entity Common Stock, Shares Outstanding"""

    concept_EntityCommonStockSharesOutstanding = instance.dts.resolve_concept(xml.QName('EntityCommonStockSharesOutstanding',namespaces['dei']))

    facts = instance.facts.filter(concept_EntityCommonStockSharesOutstanding)
    _dqc_0005(instance,error_log,suppress_errors,'DQC.US.0005.17',namespaces,facts,reporting_period_ends,operator.ge)
Esempio n. 7
0
def _dqc_0013_precondition_check(instance,namespaces,context):
    cs = xbrl.ConstraintSet(context)
    
    for name, summation in dqc_0013_preconditions.items():
        cs[xbrl.Aspect.CONCEPT] = instance.dts.resolve_concept(xml.QName(name,namespaces['us-gaap']))
        precondition_facts = instance.facts.filter(cs)
        if precondition_facts:
            val = 0
            for name in summation:
                cs[xbrl.Aspect.CONCEPT] = instance.dts.resolve_concept(xml.QName(name,namespaces['us-gaap']))
                for fact in instance.facts.filter(cs):
                    val += fact.numeric_value
            if val > 0:
                return precondition_facts[0]
    
    return None
Esempio n. 8
0
def reporting_period_ends(instance,dei_namespace):
    """Returns a dict of DocumentPeriodEndDate fact and end date tuples keyed by the legal entity domain member."""

    reporting_period_end_for_legal_entity = {}

    dim_LegalEntityAxis = instance.dts.resolve_concept(xml.QName('LegalEntityAxis',dei_namespace))
    concept_DocumentPeriodEndDate = instance.dts.resolve_concept(xml.QName('DocumentPeriodEndDate',dei_namespace))
    for fact in instance.facts.filter(concept_DocumentPeriodEndDate):
        # Amendment: Use the period end date of the context and not the DocumentPeriodEndDate value! 
        end_date = fact.period_aspect_value.end

        legal_entity = dimension_value(fact,dim_LegalEntityAxis)
        if legal_entity not in reporting_period_end_for_legal_entity or reporting_period_end_for_legal_entity[legal_entity][1] < end_date:
            reporting_period_end_for_legal_entity[legal_entity] = (fact,end_date)

    return reporting_period_end_for_legal_entity
Esempio n. 9
0
def eba_3_1(instance, error_log):
    """EBA 3.1 - Choice of Currency for Monetary facts"""
    eba_dim_CCA = instance.dts.resolve_concept(
        xml.QName('CCA', 'http://www.eba.europa.eu/xbrl/crr/dict/dim'))
    eba_dim_CUS = instance.dts.resolve_concept(
        xml.QName('CUS', 'http://www.eba.europa.eu/xbrl/crr/dict/dim'))
    eba_CA_x1 = instance.dts.resolve_concept(
        xml.QName('x1', 'http://www.eba.europa.eu/xbrl/crr/dict/dom/CA'))

    constraints = xbrl.ConstraintSet()
    constraints[eba_dim_CCA] = eba_CA_x1
    denomination_facts = instance.facts.filter(constraints)
    for fact in denomination_facts:
        if fact.concept.is_monetary():
            aspect_values = fact.aspect_values
            currency = aspect_values.get(eba_dim_CUS, None)
            if currency and currency.value.name != aspect_values[
                    xbrl.Aspect.UNIT].iso4217_currency:
                detail_error = xbrl.Error.create(
                    'For facts falling under point (b), whose context also includes the dimension “Currency with significant liabilities” (CUS), the currency of the fact (i.e. unit) MUST be consistent with the value given for this dimension.',
                    severity=xml.ErrorSeverity.INFO)
                main_error = xbrl.Error.create(
                    '[EBA.3.1] Choice of Currency for Monetary fact {fact}.',
                    fact=fact,
                    children=[detail_error])
                error_log.report(main_error)

    monetary_units = []
    for unit in instance.units:
        if unit.aspect_value.is_monetary():
            monetary_units.append(unit)
    # Optimization: Only do the single currency check if more than one monetary unit is present
    if len(monetary_units) > 1:
        single_unit = None
        for fact in instance.child_items - denomination_facts:
            if fact.concept.is_monetary():
                if single_unit is None:
                    single_unit = fact.unit
                elif fact.unit != single_unit:
                    detail_error = xbrl.Error.create(
                        'An instance MUST express all monetary facts which do not fall under point (b) using a single currency.',
                        severity=xml.ErrorSeverity.INFO)
                    main_error = xbrl.Error.create(
                        '[EBA.3.1] Choice of Currency for Monetary fact {fact}.',
                        fact=fact,
                        children=[detail_error])
                    error_log.report(main_error)
Esempio n. 10
0
def dqc_0036(instance,error_log,suppress_errors,namespaces):
    """DQC_0036 Document Period End Date Context / Fact Value Check"""

    concept_DocumentPeriodEndDate = instance.dts.resolve_concept(xml.QName('DocumentPeriodEndDate',namespaces['dei']))
    for fact1 in instance.facts.filter(concept_DocumentPeriodEndDate):
        end_date = datetime.datetime.combine(fact1.element.schema_actual_value.value,datetime.time()) + datetime.timedelta(days=1)
        if abs((end_date - fact1.period_aspect_value.end).days) > 3:
            report_error(error_log,suppress_errors,'DQC.US.0036.1',fact1=fact1)
Esempio n. 11
0
def hash_footnoteLink(link, refs):
    arcs = []
    labels = {}
    for child in link.element_children():
        if child.qname == xml.QName('loc', efm_validation.link_namespace):
            labels.setdefault(
                child.find_attribute(
                    xml.QName(
                        'label',
                        efm_validation.xlink_namespace)).normalized_value,
                []).append(child)
        elif child.qname == xml.QName('footnote',
                                      efm_validation.link_namespace):
            labels.setdefault(
                child.find_attribute(
                    xml.QName(
                        'label',
                        efm_validation.xlink_namespace)).normalized_value,
                []).append(child)
            refs['roleRefs'].add(
                child.find_attribute(
                    xml.QName(
                        'role',
                        efm_validation.xlink_namespace)).normalized_value)
        elif child.qname == xml.QName('footnoteArc',
                                      efm_validation.link_namespace):
            arcs.append(child)
            refs['arcroleRefs'].add(
                child.find_attribute(
                    xml.QName(
                        'arcrole',
                        efm_validation.xlink_namespace)).normalized_value)
        else:
            raise Exception('Unexpected element ' + str(child.qname))

    s = set()
    for arc in arcs:
        for _from in labels[arc.find_attribute(
                xml.QName('from',
                          efm_validation.xlink_namespace)).normalized_value]:
            for _to in labels[arc.find_attribute(
                    xml.QName(
                        'to',
                        efm_validation.xlink_namespace)).normalized_value]:
                s.add(
                    frozenset({
                        'arc': hash_element(arc),
                        'from': hash_element(_from),
                        'to': hash_element(_to),
                    }.items()))
    return frozenset(s)
Esempio n. 12
0
def dqc_0014(instance,error_log,suppress_errors,namespaces):
    """DQC_0014 Negative Values with No Dimensions"""
    
    for rule_id, perfix, name in dqc_0014_facts:
        concept = instance.dts.resolve_concept(xml.QName(name,namespaces.get(perfix)))
        if concept:
            for fact1 in instance.facts.filter(concept,allow_nil=False):
                if fact1.numeric_value < 0 and not has_dimensions(fact1.context):
                    report_error(error_log,suppress_errors,rule_id,fact1=fact1) 
Esempio n. 13
0
def dqc_0015(instance,error_log,suppress_errors,namespaces):
    """DQC_0015 Negative Values"""

    for rule_id, perfix, name in dqc_0015_facts:
        concept = instance.dts.resolve_concept(xml.QName(name,namespaces.get(perfix)))
        if concept:
            for fact1 in instance.facts.filter(concept,allow_nil=False):
                if fact1.numeric_value < 0 and not _dqc_0015_member_exclusions_check(fact1):
                    report_error(error_log,suppress_errors,rule_id,fact1=fact1)
Esempio n. 14
0
def eba_1_14(instance, error_log):
    """EBA 1.14 - @xsd:schemaLocation and @xsd:noNamespaceSchemaLocation"""
    attr = instance.document_element.find_attribute(
        xml.QName('schemaLocation',
                  'http://www.w3.org/2001/XMLSchema-instance'))
    if not attr:
        attr = instance.document_element.find_attribute(
            xml.QName('noNamespaceSchemaLocation',
                      'http://www.w3.org/2001/XMLSchema-instance'))
    if attr:
        detail_error = xbrl.Error.create(
            '@xsd:schemaLocation or @xsd:noNamespaceSchemaLocation MUST NOT be used.',
            severity=xml.ErrorSeverity.INFO)
        main_error = xbrl.Error.create(
            '[EBA.1.14] @xsd:schemaLocation and @xsd:noNamespaceSchemaLocation.',
            location=attr,
            children=[detail_error])
        error_log.report(main_error)
Esempio n. 15
0
def hash_instance(elem):
    refs = {
        'contexts': set(),
        'units': set(),
        'roleRefs': set(),
        'arcroleRefs': set(),
        'footnoteLinks': set()
    }
    refElems = {
        'contexts': {},
        'units': {},
        'roleRefs': {},
        'arcroleRefs': {},
        'footnoteLinks': {}
    }
    s = set()
    for child in elem.element_children():
        if child.qname == xml.QName('schemaRef',
                                    efm_validation.link_namespace):
            s.add(hash_element(child))
        elif child.qname == xml.QName('linkbaseRef',
                                      efm_validation.link_namespace):
            s.add(hash_element(child))
        elif child.qname == xml.QName('roleRef',
                                      efm_validation.link_namespace):
            refElems['roleRefs'][child.find_attribute(
                'roleURI').normalized_value] = hash_element(child)
        elif child.qname == xml.QName('arcroleRef',
                                      efm_validation.link_namespace):
            refElems['arcroleRefs'][child.find_attribute(
                'arcroleURI').normalized_value] = hash_element(child)
        elif child.qname == xml.QName('context',
                                      efm_validation.xbrli_namespace):
            refElems['contexts'][child.find_attribute(
                'id').normalized_value] = hash_element(child)
        elif child.qname == xml.QName('unit', efm_validation.xbrli_namespace):
            refElems['units'][child.find_attribute(
                'id').normalized_value] = hash_element(child)
        elif child.qname == xml.QName('footnoteLink',
                                      efm_validation.link_namespace):
            role = child.find_attribute(
                xml.QName('role',
                          efm_validation.xlink_namespace)).normalized_value
            refs['roleRefs'].add(role)
            refs['footnoteLinks'].add(role)
            refElems['footnoteLinks'][role] = refElems['footnoteLinks'].get(
                role, frozenset()) | hash_footnoteLink(child, refs)
        else:
            s.add(hash_element(child, refs))
    for key in refs.keys():
        for ref in refs[key]:
            if ref in refElems[key]:
                s.add(refElems[key][ref])
    return frozenset(s)
Esempio n. 16
0
def dqc_0005_48(instance,error_log,suppress_errors,namespaces,reporting_period_ends):
    """DQC_0005.48 Subsequent events"""

    dim_SubsequentEventTypeAxis = instance.dts.resolve_concept(xml.QName('SubsequentEventTypeAxis',namespaces.get('us-gaap')))
    if dim_SubsequentEventTypeAxis:

        cs = xbrl.ConstraintSet()
        cs[dim_SubsequentEventTypeAxis] = xbrl.ExplicitDimensionAspectValue(dim_SubsequentEventTypeAxis,None)
        facts = instance.facts - instance.facts.filter(cs)
        _dqc_0005(instance,error_log,suppress_errors,'DQC.US.0005.48',namespaces,facts,reporting_period_ends,operator.gt,{'us-gaap:SubsequentEventTypeAxis':dim_SubsequentEventTypeAxis})
Esempio n. 17
0
def dqc_0033(instance,error_log,suppress_errors,namespaces):
    """DQC_0033 Document Period End Date Context"""

    dei_namespace = namespaces['dei']
    dim_LegalEntityAxis = instance.dts.resolve_concept(xml.QName('LegalEntityAxis',dei_namespace))

    reporting_periods = {}
    concept_DocumentPeriodEndDate = instance.dts.resolve_concept(xml.QName('DocumentPeriodEndDate',dei_namespace))
    for fact1 in instance.facts.filter(concept_DocumentPeriodEndDate):
        end_date = datetime.datetime.combine(fact1.element.schema_actual_value.value,datetime.time()) + datetime.timedelta(days=1)
        is_valid = abs((end_date - fact1.period_aspect_value.end).days) <= 3
        legal_entity = dimension_value(fact1,dim_LegalEntityAxis)
        reporting_periods[legal_entity] = (fact1,is_valid)

    for fact1 in facts_in_namespace(instance,dei_namespace,('EntityCommonStockSharesOutstanding','EntityPublicFloat','DocumentPeriodEndDate','EntityNumberOfEmployees','EntityListingDepositoryReceiptRatio')):

        reporting_period = reporting_periods.get(dimension_value(fact1,dim_LegalEntityAxis))
        if not reporting_period:
            reporting_period = reporting_periods.get(dim_LegalEntityAxis.default_member)

        if reporting_period and reporting_period[1] and period_end(fact1) != period_end(reporting_period[0]):
            report_error(error_log,suppress_errors,'DQC.US.0033.2',**{'fact1':fact1,'dei:DocumentPeriodEndDate':reporting_period[0]})
Esempio n. 18
0
def dqc_0005(instance,error_log,suppress_errors,namespaces):
    """DQC_0005 Context Dates After Period End Date"""

    concept_DocumentType = instance.dts.resolve_concept(xml.QName('DocumentType',namespaces['dei']))
    facts_DocumentType = instance.facts.filter(concept_DocumentType)
    if len(facts_DocumentType) != 1 or facts_DocumentType[0].normalized_value in ('S-1', 'S-3', 'S-4', 'S-6', 'S-8', 'S-11', 'S-20', 'S-1/A', 'S-3/A', 'S-4/A', 'S-6/A', 'S-8/A', 'S-11/A', 'S-20/A'):
        # Appendix A
        # Exclusions from the rule: S-1, S-3, S-4, S-6, S-8, S-11, S-20, S-1/A, S-3/A, S-4/A, S-6/A, S-8/A, S-11/A and S-20/A
        return
    
    reporting_periods = reporting_period_ends(instance,namespaces['dei'])
    dqc_0005_17(instance,error_log,suppress_errors,namespaces,reporting_periods)
    dqc_0005_48(instance,error_log,suppress_errors,namespaces,reporting_periods)
    dqc_0005_49(instance,error_log,suppress_errors,namespaces,reporting_periods)
Esempio n. 19
0
def eba_2_1(instance, error_log):
    """EBA 2.1 - The existence of xml:base is not permitted"""
    for elem in dfs(instance.document_element):
        xml_base_attr = elem.find_attribute(
            xml.QName('base', 'http://www.w3.org/XML/1998/namespace'))
        if xml_base_attr:
            detail_error = xbrl.Error.create(
                'The attribute @xml:base MUST NOT appear in any instance document. [EFM13, p. 6-7].',
                severity=xml.ErrorSeverity.INFO)
            main_error = xbrl.Error.create(
                '[EBA.2.1] The existence of {xml_base} is not permitted.',
                xml_base=xml_base_attr,
                children=[detail_error])
            error_log.report(main_error)
Esempio n. 20
0
def dqc_0006(instance,error_log,suppress_errors,namespaces):
    """DQC_0006 DEI and Block Tag Date Contexts"""

    concept_DocumentType = instance.dts.resolve_concept(xml.QName('DocumentType',namespaces['dei']))
    facts_DocumentType = instance.facts.filter(concept_DocumentType)
    if len(facts_DocumentType) != 1 or facts_DocumentType[0].normalized_value.endswith('T') or facts_DocumentType[0].normalized_value.endswith('T/A'):
        # This rule also does not test any transition period filings, which are identified by the letter "T" in the form name.
        # Transition period filings are submitted when a filer changes their fiscal year.
        # Transition period filings may cover periods which are different from the general quarter or annual length.
        return

    dim_LegalEntityAxis = instance.dts.resolve_concept(xml.QName('LegalEntityAxis',namespaces['dei']))
    concept_DocumentFiscalPeriodFocus = instance.dts.resolve_concept(xml.QName('DocumentFiscalPeriodFocus',namespaces['dei']))

    period_focus_for_legal_entity = {}
    for fact in instance.facts.filter(concept_DocumentFiscalPeriodFocus):
        period_focus_for_legal_entity[dimension_value(fact,dim_LegalEntityAxis)] = fact

    fact_names = [
        'AmendmentDescription',
        'AmendmentFlag',
        'CurrentFiscalYearEndDate',
        'DocumentPeriodEndDate',
        'DocumentFiscalYearFocus',
        'DocumentFiscalPeriodFocus',
        'DocumentType',
        'EntityRegistrantName',
        'EntityCentralIndexKey',
        'EntityFilerCategory',
    ]

    for name in fact_names:
        concept = instance.dts.resolve_concept(xml.QName(name,namespaces['dei']))
        if concept:
            _dqc_0006(instance,error_log,suppress_errors,dim_LegalEntityAxis,period_focus_for_legal_entity,instance.facts.filter(concept))

    _dqc_0006(instance,error_log,suppress_errors,dim_LegalEntityAxis,period_focus_for_legal_entity,textblock_facts(instance))
Esempio n. 21
0
def dqc_0013(instance,error_log,suppress_errors,namespaces):
    """DQC_0013 Negative Values with Dependence"""

    cache = {}
    for rule_id, perfix, name in dqc_0013_facts:
        concept = instance.dts.resolve_concept(xml.QName(name,namespaces.get(perfix)))
        if concept:
            for fact1 in instance.facts.filter(concept,allow_nil=False):
                if fact1.numeric_value < 0 and not _dqc_0015_member_exclusions_check(fact1):
                    if fact1.context in cache:
                        precondition_fact = cache[fact1.context]
                    else:
                        precondition_fact = _dqc_0013_precondition_check(instance,namespaces,fact1.context)
                        cache[fact1.context] = precondition_fact
                    if precondition_fact:
                        report_error(error_log,suppress_errors,rule_id,fact1=fact1,preconditionfact=precondition_fact)
Esempio n. 22
0
def eba_1_6(instance, error_log):
    """EBA 1.6 - Filing indicators"""

    # Get all filing indicators which are present in the taxonomy
    available_indicators = set()
    for table in instance.dts.tables:
        for label in table.labels(
                label_role=
                'http://www.eurofiling.info/xbrl/role/filing-indicator-code'):
            available_indicators.add(label.text)

    used_indictors = {}
    indicator_facts = instance.facts.filter(
        xml.QName('filingIndicator',
                  'http://www.eurofiling.info/xbrl/ext/filing-indicators'))
    for indicator in indicator_facts:
        if indicator.context.entity.segment or indicator.context.scenario:
            detail_error = xbrl.Error.create(
                'The context referenced by the filing indicator elements MUST NOT contain xbrli:segment or xbrli:scenario elements.',
                severity=xml.ErrorSeverity.INFO)
            main_error = xbrl.Error.create('[EBA.1.6] Filing indicators.',
                                           location=indicator,
                                           children=[detail_error])
            error_log.report(main_error)

        if used_indictors.setdefault(indicator.normalized_value,
                                     indicator) != indicator:
            detail_error = xbrl.Error.create(
                'Reported XBRL instances MUST contain only one filing indicator element for a given reporting unit("template").',
                severity=xml.ErrorSeverity.INFO)
            main_error = xbrl.Error.create(
                '[EBA.1.6.1] Multiple filing indicators for the same reporting unit.',
                location=indicator,
                children=[detail_error])
            error_log.report(main_error)

        if indicator.normalized_value not in available_indicators:
            detail_error = xbrl.Error.create(
                'The values of filing indicators MUST only be those given by the label resources with the role http://www.eurofiling.info/xbrl/role/filing-indicator-code applied to the relevant tables in the XBRL taxonomy4 for that reporting module (entry point). Filing indicator values must be formatted correctly (for example including any underscore characters).',
                severity=xml.ErrorSeverity.INFO)
            main_error = xbrl.Error.create(
                '[EBA.1.6.3] Filing indicator codes.',
                location=indicator,
                children=[detail_error])
            error_log.report(main_error)
Esempio n. 23
0
def textblock_facts(instance):
    """Returns an xbrl.FactSet object with facts whose concept's item type is or is derived from textBlockItemType."""
    facts = xbrl.FactSet()

    type_textBlockItemType = instance.dts.schema.resolve_type_definition(xml.QName('textBlockItemType','http://www.xbrl.org/dtr/type/non-numeric'))
    if type_textBlockItemType:

        is_textblock_cache = {}
        for fact in instance.facts:
            is_textblock = is_textblock_cache.get(fact.concept,None)
            if is_textblock is None:
                is_textblock = fact.concept.type_definition.is_derived_from(type_textBlockItemType)
                is_textblock_cache[fact.concept] = is_textblock

            if is_textblock:
                facts.add(fact)

    return facts
Esempio n. 24
0
def execute_variation(testcase, variation):
    """Peforms the actual XBRL instance or taxonomy validation and returns 'PASS' if the actual outcome is conformant with the result specified in the variation."""
    logging.info('[%s%s] Start executing variation', testcase['number'],
                 variation['id'])

    if len(variation['data']['instances']) > 1:
        logging.info('[%s%s] Skipped multiple instance variation',
                     testcase['number'], variation['id'])
        return 'SKIP', collections.Counter()
    if any(_assert['num'] in ('60302', '60310')
           for _assert in variation['result']['asserts']):
        logging.info('[%s%s] Skipped variation containing submission check',
                     testcase['number'], variation['id'])
        return 'SKIP', collections.Counter()
    if any(_assert['num'].startswith('626')
           for _assert in variation['result']['asserts']):
        logging.info(
            '[%s%s] Skipped variation containing syntax related to rendering check',
            testcase['number'], variation['id'])
        return 'SKIP', collections.Counter()
    if variation['id'] == '_304ng' and testcase['number'] == '525-00':
        logging.info(
            '[%s%s] Skipped variation containing internal arelle error check',
            testcase['number'], variation['id'])
        return 'SKIP', collections.Counter()

    if 'readMeFirst' not in variation['data']:
        raise RuntimeError('Unknown entry point in variation %s%s' %
                           (testcase['number'], variation['id']))

    uri = variation['data']['readMeFirst']
    logging.info('[%s%s] Validating instance %s', testcase['number'],
                 variation['id'], uri)

    # Determine if UTR checks should be enabled
    bEnableUTR = False
    forceUtrValidationParam = [
        param for param in variation['data']['parameters']
        if param['name'] == 'forceUtrValidation'
    ]
    if forceUtrValidationParam:
        bEnableUTR = forceUtrValidationParam[0]['value'] == 'true'
    else:
        dts, _ = xbrl.taxonomy.DTS.create_from_url(
            schema['uri'] for schema in variation['data']['schemas'])
        if dts and dts.resolve_concept(
                xml.QName('UTR', 'http://xbrl.sec.gov/dei/2014-01-31')):
            bEnableUTR = True

    bNotEDGARDependent = 'Not EDGAR Dependent' in testcase['name']
    has_ixbrl_warnings = False
    has_ixbrl_errors = False
    instance = None
    if os.path.splitext(uri)[1] == '.htm':
        # Do Inline XBRL transformation
        if bNotEDGARDependent:
            instances, error_log = xbrl.InlineXBRLDocumentSet.transform_xml_from_url(
                uri)
        else:
            instance, error_log = xml.Instance.create_from_url(
                uri, schema=xhtml_inlinexbrl_xsd)
            efm_validation.validate_ixbrl(instance, error_log)
            if error_log.has_warnings():
                has_ixbrl_warnings = True
            if not error_log.has_errors():
                instances, error_log = xbrl.InlineXBRLDocumentSet.transform_xbrl_from_url(
                    uri, utr=utr if bEnableUTR else None)
                instance = instances.get(None)
        if error_log.has_errors():
            has_ixbrl_errors = True
    else:
        instance, error_log = xbrl.Instance.create_from_url(
            uri, utr=utr if bEnableUTR else None)

    if not bNotEDGARDependent and not has_ixbrl_errors:
        efm_validation.validate(
            uri, instance, error_log, {
                param['name']: param['value']
                for param in variation['data']['parameters']
            })

    if error_log.has_errors() and logging.getLogger().isEnabledFor(
            logging.DEBUG):
        logging.debug('[%s%s] Error log:\n%s', testcase['number'],
                      variation['id'],
                      '\n'.join(error.text for error in error_log))

    error_counts = {
        'err': collections.Counter(),
        'wrn': collections.Counter(),
    }

    if has_ixbrl_errors:
        error_counts['err']['99999'] += 1
    elif has_ixbrl_warnings:
        error_counts['wrn']['99999'] += 1
    else:
        for error in error_log:
            if error.severity == xml.ErrorSeverity.ERROR:
                severity = 'err'
            elif error.severity == xml.ErrorSeverity.WARNING:
                severity = 'wrn'
            else:
                continue
            m = re_error_code.search(error.text)
            if m:
                code = '{}{:02d}{:02d}'.format(
                    *[int(x) for x in m.group(1).split('.')])
                error_counts[severity][code] += 1
            else:
                mlax = re_error_code_lax.search(error.text)
                if mlax:
                    error_counts[severity][mlax.group(0)] += 1
                else:
                    error_counts[severity]['other'] += 1

    passed = False if not any(_assert['severity'] == 'err'
                              for _assert in variation['result']
                              ['asserts']) and error_log.has_errors() else True
    for _assert in variation['result']['asserts']:
        if error_counts[_assert['severity']][_assert['num']] == 0:
            passed = False
            if _assert['num'] == '60304' and error_counts[
                    _assert['severity']]['60403'] > 0:
                # References to predefined HTML entities are already reported on XML well-formedness level. So we report EFM 6.4.3 (invalid XBRL).
                passed = True
            elif _assert['num'] == '60305' and (
                    error_counts[_assert['severity']]['[EFM.5.2.1.1]'] > 0
                    or error_counts[_assert['severity']]['60403'] > 0):
                # Invalid entitiy references are already reported on XML well-formedness level. So we report EFM 6.4.3 (invalid XBRL).
                # Invalid characters in iXBRL are reported as 5.2.1.1 (see testcases 603-05_004ng to 603-05_006ng).
                passed = True
            elif _assert['num'] == '60535' and error_counts[
                    _assert['severity']]['60403'] > 0:
                # UTR checks are done by XBRL validation. Therefore we report EFM 6.4.3 (invalid XBRL).
                passed = True
            elif _assert['num'] == '60502' and error_counts[
                    _assert['severity']]['60403'] > 0:
                # CIK syntax check is done by xs:pattern during XML schema validation. Therefore we report EFM 6.4.3 (invalid XBRL).
                passed = True
            elif _assert['num'] == '60516' and error_counts[
                    _assert['severity']]['60515'] > 0:
                # References to unspecified entities cause XML wellformed check to fail. Therefore we report EFM 6.5.15 for test 605-15_003ng.
                passed = True
            elif _assert['num'] == '62202' and error_counts[
                    _assert['severity']]['60403'] > 0:
                # Some of the unsupported locations referenced by the testsuite aren't available on the net all the time. Therefore we permit also EFM 6.4.3 (invalid XBRL) for these cases.
                passed = True
            elif _assert['num'] == '60527' and error_counts[
                    _assert['severity']]['60403'] > 0:
                # Testcase 605-27_003ng has a custom locator in a standard link. This is already reported as EFM 6.4.3 (invalid XBRL).
                passed = True

    conformance = 'PASS' if passed else 'FAIL'

    if passed and instance is not None and 'instance' in variation[
            'result'].keys():
        ref_instance, ref_error_log = xbrl.Instance.create_from_url(
            variation['result']['instance'])
        if ref_instance is not None:
            if not cmp_output(ref_instance.document_element,
                              instance.document_element):
                conformance = 'OUTPUT MISMATCH'

    error_counts = error_counts['err'] + error_counts['wrn']
    logging.info('[%s%s] Finished executing variation: %s, %s',
                 testcase['number'], variation['id'], conformance,
                 dict(error_counts))
    return conformance, error_counts
Esempio n. 25
0
def hash_element(elem, refs=None):
    d = {'name': elem.qname, 'value': hash_element_content(elem, refs)}
    exclude_attrs = [
        xml.QName('label', efm_validation.xlink_namespace),
        xml.QName('from', efm_validation.xlink_namespace),
        xml.QName('to', efm_validation.xlink_namespace),
        xml.QName('order')
    ]
    if elem.qname == xml.QName('schemaRef', efm_validation.link_namespace):
        exclude_attrs.append(
            xml.QName('arcrole', efm_validation.xlink_namespace))
    if elem.qname != xml.QName('footnote', efm_validation.link_namespace):
        exclude_attrs.append(xml.QName('lang', efm_validation.xml_namespace))
    for attr in elem.attributes:
        if attr.qname not in exclude_attrs:
            value = attr.schema_actual_value if attr.schema_actual_value is not None else attr.normalized_value
            d[attr.qname] = value
            if refs is not None:
                if attr.qname == xml.QName('contextRef'):
                    refs['contexts'].add(value)
                elif attr.qname == xml.QName('unitRef'):
                    refs['units'].add(value)
                elif attr.qname == xml.QName('role',
                                             efm_validation.xlink_namespace):
                    refs['roleRefs'].add(value)
                elif attr.qname == xml.QName('arcrole',
                                             efm_validation.xlink_namespace):
                    refs['arcroleRefs'].add(value)
    return frozenset(d.items())
def execute_variation(testcase, variation):
    """Peforms the actual XBRL instance or taxonomy validation and returns 'PASS' if the actual outcome is conformant with the result specified in the variation."""
    logging.info('[%s%s] Start executing variation', testcase['number'],
                 variation['id'])

    if len(variation['data']['instances']) > 1:
        logging.info('[%s%s] Skipped multiple instance variation',
                     testcase['number'], variation['id'])
        return 'SKIP', collections.Counter()
    if any(_assert['num'] in ('60302', '60310')
           for _assert in variation['result']['asserts']):
        logging.info('[%s%s] Skipped variation containing submission check',
                     testcase['number'], variation['id'])
        return 'SKIP', collections.Counter()

    if 'readMeFirst' not in variation['data']:
        raise RuntimeError('Unknown entry point in variation %s%s' %
                           (testcase['number'], variation['id']))

    uri = variation['data']['readMeFirst']
    logging.info('[%s%s] Validating instance %s', testcase['number'],
                 variation['id'], uri)

    # Determine if UTR checks should be enabled
    bEnableUTR = False
    forceUtrValidationParam = [
        param for param in variation['data']['parameters']
        if param['name'] == 'forceUtrValidation'
    ]
    if forceUtrValidationParam:
        bEnableUTR = forceUtrValidationParam[0]['value'] == 'true'
    else:
        dts = xbrl.taxonomy.DTS.create_from_url(
            schema['uri'] for schema in variation['data']['schemas'])[0]
        if dts and dts.resolve_concept(
                xml.QName('UTR', 'http://xbrl.sec.gov/dei/2014-01-31')):
            bEnableUTR = True

    bNotEDGARDependent = 'Not EDGAR Dependent' in testcase['name']
    has_ixbrl_warnings = False
    has_ixbrl_errors = False
    instance = None
    if os.path.splitext(uri)[1] == '.htm':
        # Do Inline XBRL transformation
        if bNotEDGARDependent:
            instances, error_log = xbrl.InlineXBRLDocumentSet.transform_xml_from_url(
                uri, utr=True)
        else:
            instance, error_log = xml.Instance.create_from_url(
                uri, schema=xhtml_inlinexbrl_xsd)
            efm_validation.validate_ixbrl(instance, error_log)
            if error_log.has_warnings():
                has_ixbrl_warnings = True
            if not error_log.has_errors():
                instances, error_log = xbrl.InlineXBRLDocumentSet.transform_xbrl_from_url(
                    uri, utr=bEnableUTR)
                instance = instances.get(None)
        if error_log.has_errors():
            has_ixbrl_errors = True
    else:
        instance, error_log = xbrl.Instance.create_from_url(uri,
                                                            utr=bEnableUTR)

    if not bNotEDGARDependent and not has_ixbrl_errors:
        efm_validation.validate(
            uri, instance, error_log, {
                param['name']: param['value']
                for param in variation['data']['parameters']
            })

    if error_log.has_errors() and logging.getLogger().isEnabledFor(
            logging.DEBUG):
        logging.debug('[%s%s] Error log:\n%s', testcase['number'],
                      variation['id'],
                      '\n'.join(error.text for error in error_log))

    error_counts = {
        'err': collections.Counter(),
        'wrn': collections.Counter(),
    }

    if has_ixbrl_errors:
        error_counts['err']['99999'] += 1
    elif has_ixbrl_warnings:
        error_counts['wrn']['99999'] += 1
    else:
        for error in error_log:
            if error.severity == xml.ErrorSeverity.ERROR:
                severity = 'err'
            elif error.severity == xml.ErrorSeverity.WARNING:
                severity = 'wrn'
            else:
                continue
            m = re_error_code.search(error.text)
            if m:
                code = '{}{:02d}{:02d}'.format(
                    *[int(x) for x in m.group(1).split('.')])
                error_counts[severity][code] += 1
            else:
                error_counts[severity]['other'] += 1

    passed = False if not any(_assert['severity'] == 'err'
                              for _assert in variation['result']
                              ['asserts']) and error_log.has_errors() else True
    for _assert in variation['result']['asserts']:
        if error_counts[_assert['severity']][_assert['num']] == 0:
            passed = False

    conformance = 'PASS' if passed else 'FAIL'

    if passed and instance is not None and 'instance' in variation[
            'result'].keys():
        ref_instance, ref_error_log = xbrl.Instance.create_from_url(
            variation['result']['instance'])
        if ref_instance is not None:
            if not cmp_output(ref_instance.document_element,
                              instance.document_element):
                conformance = 'OUTPUT MISMATCH'

    error_counts = error_counts['err'] + error_counts['wrn']
    logging.info('[%s%s] Finished executing variation: %s, %s',
                 testcase['number'], variation['id'], conformance,
                 dict(error_counts))
    return conformance, error_counts
Esempio n. 27
0
def dqc_0041(instance,error_log,suppress_errors,namespaces):
    """DQC_0041 Axis with a Default Member that Differs from the US GAAP Taxonomy"""

    for dim in instance.dts.dimensions:
        if dim.is_explicit():
            default_member = dim.default_member
            if not default_member:
                continue
            usgaap_default_member = dqc_0041_default_members.get(dim.target_namespace,{}).get(dim.name)
            if usgaap_default_member and default_member.name != usgaap_default_member:
                report_error(error_log,suppress_errors,'DQC.US.0041.73',axis=dim,axis_default=instance.dts.resolve_concept(xml.QName(usgaap_default_member,dim.target_namespace)),default=default_member)