Ejemplo n.º 1
0
 def __init__(self, modelXbrl, tabWin, arcrole, linkrole=None, linkqname=None, arcqname=None, lang=None, treeColHdr=None):
     super().__init__(modelXbrl, tabWin, XbrlConst.baseSetArcroleLabel(arcrole)[1:], True, lang)
     self.arcrole = arcrole
     self.linkrole = linkrole
     self.linkqname = linkqname
     self.arcqname = arcqname
     self.treeColHdr = treeColHdr
Ejemplo n.º 2
0
 def insertResources(self):
     self.showStatus("insert resources")
     table = self.getTable('resource', 'resource_id', 
                           ('role_uri_id', 'qname_id', 'document_id', 'document_line_number', 'document_column_number'), 
                           ('role_uri_id', 'qname_id', 'document_id', 'document_line_number', 'document_column_number'), 
                           tuple((self.uriId[resource.role],
                                  self.qnameId[resource.qname],
                                  self.documentIds[resource.modelDocument.uri],
                                  resource.sourceline,
                                  0)
                                 for arcrole in (XbrlConst.conceptLabel, XbrlConst.conceptReference)
                                 for rel in self.modelXbrl.relationshipSet(arcrole).modelRelationships
                                 for resource in (rel.fromModelObject, rel.toModelObject)
                                 if isinstance(resource, ModelResource)))
     self.resourceId = dict(((roleId, qnId, docId, line, offset), id)
                            for id, roleId, qnId, docId, line, offset in table)
     
     self.showStatus("insert labels")
     table = self.getTable('label_resource', 'resource_id', 
                           ('resource_id', 'label', 'xml_lang'), 
                           ('resource_id',), 
                           tuple((self.resourceId[self.uriId[resource.role],
                                                  self.qnameId[resource.qname],
                                                  self.documentIds[resource.modelDocument.uri],
                                                  resource.sourceline,
                                                  0],
                                  resource.elementText,
                                  resource.xmlLang)
                                 for arcrole in (XbrlConst.conceptLabel, XbrlConst.conceptReference)
                                 for rel in self.modelXbrl.relationshipSet(arcrole).modelRelationships
                                 for resource in (rel.fromModelObject, rel.toModelObject)
                                 if isinstance(resource, ModelResource) and XbrlConst.isLabelRole(resource.role)))
Ejemplo n.º 3
0
 def __init__(self,
              modelXbrl,
              tabWin,
              arcrole,
              linkrole=None,
              linkqname=None,
              arcqname=None,
              lang=None,
              treeColHdr=None,
              showLinkroles=True,
              showRelationships=True,
              showColumns=True,
              expandAll=False,
              hasTableIndex=False):
     self.isEbaTableIndex = False
     if isinstance(arcrole, (list, tuple)):
         tabName = arcrole[0]
     else:
         tabName = XbrlConst.baseSetArcroleLabel(arcrole)[1:]
     tabName = tabName + " (" + modelXbrl.getInstanceFilenameForView() + ")"
     super(ViewRelationshipSet, self).__init__(modelXbrl, tabWin, tabName,
                                               True, lang)
     self.arcrole = arcrole
     self.linkrole = linkrole
     self.linkqname = linkqname
     self.arcqname = arcqname
     self.treeColHdr = treeColHdr
     self.showLinkroles = showLinkroles
     self.showRelationships = showRelationships
     self.showColumns = showColumns
     self.expandAllOnFirstDisplay = expandAll
     self.hasTableIndex = hasTableIndex
     self.isResourceArcrole = False
Ejemplo n.º 4
0
def ebaDecimals(locale, value, concept, defaultDecimals):
    '''
    :type locale: dict
    :type value: string
    :type concept: ModelConcept
    :type defaultDecimals: str
    :rtype (boolean, str)
    '''
    isPercent = concept.typeQname == qnPercentItemType
    isInteger = XbrlConst.isIntegerXsdType(concept.type.baseXsdType)
    isMonetary = concept.isMonetary
    decimalsFound, decimals = decimalsComputer(locale, value, concept, defaultDecimals)
    if not(decimalsFound) or decimals == 'INF':
        return (decimalsFound, decimals)
    else:
        # the default values are for non-monetary items
        lowerBound = -20
        upperBound = 20
        decimalsAsInteger = int(decimals)
        if isMonetary:
            lowerBound = -3
        elif isInteger:
            lowerBound = upperBound = 0
        elif isPercent: # percent values
            lowerBound = 4
            upperBound = 20
        if decimalsAsInteger<lowerBound:
            decimals = str(lowerBound)
            decimalsAsInteger = lowerBound
        if decimalsAsInteger>upperBound:
            decimals = 'INF' # approximation
            decimalsAsInteger = upperBound
        return (decimalsFound, decimals)
Ejemplo n.º 5
0
 def __init__(
     self,
     modelXbrl,
     tabWin,
     arcrole,
     linkrole=None,
     linkqname=None,
     arcqname=None,
     lang=None,
     treeColHdr=None,
     showLinkroles=True,
     showRelationships=True,
     showColumns=True,
     expandAll=False,
     hasTableIndex=False,
 ):
     if isinstance(arcrole, (list, tuple)):
         tabName = arcrole[0]
     else:
         tabName = XbrlConst.baseSetArcroleLabel(arcrole)[1:]
     super(ViewRelationshipSet, self).__init__(modelXbrl, tabWin, tabName, True, lang)
     self.arcrole = arcrole
     self.linkrole = linkrole
     self.linkqname = linkqname
     self.arcqname = arcqname
     self.treeColHdr = treeColHdr
     self.showLinkroles = showLinkroles
     self.showRelationships = showRelationships
     self.showColumns = showColumns
     self.expandAllOnFirstDisplay = expandAll
     self.hasTableIndex = hasTableIndex
     self.isResourceArcrole = False
Ejemplo n.º 6
0
    def view(self, arcrole, linkrole=None, linkqname=None, arcqname=None):
        # determine relationships indent depth for dimensions linkbases
        # set up treeView widget and tabbed pane
        if arcrole == XbrlConst.parentChild: # extra columns
            heading = ["Presentation Relationships", "Pref. Label", "Type", "References"]
        elif arcrole == XbrlConst.summationItem:    # add columns for calculation relationships
            heading = ["Calculation Relationships", "Weight", "Balance"]
        elif arcrole == "XBRL-dimensions":    # add columns for dimensional information
            heading = ["Dimensions Relationships", "Arcrole","CntxElt","Closed","Usable"]
        elif arcrole == "Table-rendering":
            heading = ["Table Relationships", "Axis", "Abs", "Mrg", "Header", "Primary Item", "Dimensions"]
        elif isinstance(arcrole, (list,tuple)) or XbrlConst.isResourceArcrole(arcrole):
            self.isResourceArcrole = True
            self.showReferences = isinstance(arcrole, _STR_BASE) and arcrole.endswith("-reference")
            heading = ["Resource Relationships", "Arcrole","Resource","ResourceRole","Language"]
        else:
            heading = [os.path.basename(arcrole).title() + " Relationships"]
        # relationship set based on linkrole parameter, to determine applicable linkroles
        relationshipSet = self.modelXbrl.relationshipSet(arcrole, linkrole, linkqname, arcqname)

        self.arcrole = arcrole
        self.maxNumDims = 1
            
        if relationshipSet:
            # sort URIs by definition
            linkroleUris = []
            for linkroleUri in relationshipSet.linkRoleUris:
                modelRoleTypes = self.modelXbrl.roleTypes.get(linkroleUri)
                if modelRoleTypes:
                    roledefinition = (modelRoleTypes[0].genLabel(lang=self.lang, strip=True) or modelRoleTypes[0].definition or linkroleUri)                    
                else:
                    roledefinition = linkroleUri
                linkroleUris.append((roledefinition, linkroleUri))
            linkroleUris.sort()
    
            for roledefinition, linkroleUri in linkroleUris:
                linkRelationshipSet = self.modelXbrl.relationshipSet(arcrole, linkroleUri, linkqname, arcqname)
                for rootConcept in linkRelationshipSet.rootConcepts:
                    self.treeDepth(rootConcept, rootConcept, 2, arcrole, linkRelationshipSet, set())

        # avoid use of lastColSpan, html and excel do not use multiple cols for dimensions for now
        #if "Dimensions" == heading[-1]:
        #    lastColSpan = self.maxNumDims
        #else:
        lastColSpan = None
                    
        self.addRow(heading, asHeader=True, lastColSpan=lastColSpan) # must do after determining tree depth
        self.setColWidths([COL_WIDTHS.get(hdg, 80 if hdg.endswith("  Relationships") else 8) for hdg in heading])
        
        if relationshipSet:
            # for each URI in definition order
            for roledefinition, linkroleUri in linkroleUris:
                #Deepak-Khopade-isdr: 15-Feb-2017 added "roleDefinition" to see it on presentation tree
                attr = {"roleUri": linkroleUri, "roleDefinition": roledefinition}
                self.addRow([roledefinition], treeIndent=0, colSpan=len(heading), 
                            xmlRowElementName="linkRole", xmlRowEltAttr=attr, xmlCol0skipElt=True)
                linkRelationshipSet = self.modelXbrl.relationshipSet(arcrole, linkroleUri, linkqname, arcqname)
                for rootConcept in linkRelationshipSet.rootConcepts:
                    self.viewConcept(rootConcept, rootConcept, "", self.labelrole, 1, arcrole, linkRelationshipSet, set())
Ejemplo n.º 7
0
def labelroles(modelXbrl, includeConceptName=False):
    # returns sorted list of tuples of arcrole basename and uri
    return sorted(
        set(
            (XbrlConst.labelroleLabel(r), r)
            for r in (modelXbrl.labelroles | ({XbrlConst.conceptNameLabelRole} if includeConceptName else set()))
        )
    )
Ejemplo n.º 8
0
 def __init__(self, modelXbrl, tabWin, arcrole, linkrole=None, linkqname=None, arcqname=None, lang=None, treeColHdr=None):
     if isinstance(arcrole, (list,tuple)):
         tabName = arcrole[0]
     else:
         tabName = XbrlConst.baseSetArcroleLabel(arcrole)[1:]
     super(ViewRelationshipSet, self).__init__(modelXbrl, tabWin, tabName, True, lang)
     self.arcrole = arcrole
     self.linkrole = linkrole
     self.linkqname = linkqname
     self.arcqname = arcqname
     self.treeColHdr = treeColHdr
     self.isResourceArcrole = False
Ejemplo n.º 9
0
    def view(self, arcrole, linkrole=None, linkqname=None, arcqname=None):
        # determine relationships indent depth for dimensions linkbases
        # set up treeView widget and tabbed pane
        if arcrole == XbrlConst.parentChild: # extra columns
            heading = ["Presentation Relationships", "Pref. Label", "Type", "References"]
        elif arcrole == XbrlConst.summationItem:    # add columns for calculation relationships
            heading = ["Calculation Relationships", "Weight", "Balance"]
        elif arcrole == "XBRL-dimensions":    # add columns for dimensional information
            heading = ["Dimensions Relationships", "Arcrole","CntxElt","Closed","Usable"]
        elif isinstance(arcrole, (list,tuple)) or XbrlConst.isResourceArcrole(arcrole):
            self.isResourceArcrole = True
            self.showReferences = isinstance(arcrole, _STR_BASE) and arcrole.endswith("-reference")
            heading = ["Resource Relationships", "Arcrole","Resource","ResourceRole","Language"]
        else:
            heading = [os.path.basename(arcrole).title() + " Relationships"]
        # relationship set based on linkrole parameter, to determine applicable linkroles
        relationshipSet = self.modelXbrl.relationshipSet(arcrole, linkrole, linkqname, arcqname)

        self.arcrole = arcrole
        
        if relationshipSet:
            # sort URIs by definition
            linkroleUris = []
            for linkroleUri in relationshipSet.linkRoleUris:
                modelRoleTypes = self.modelXbrl.roleTypes.get(linkroleUri)
                if modelRoleTypes:
                    roledefinition = (modelRoleTypes[0].genLabel(lang=self.lang, strip=True) or modelRoleTypes[0].definition or linkroleUri)                    
                else:
                    roledefinition = linkroleUri
                linkroleUris.append((roledefinition, linkroleUri))
            linkroleUris.sort()
    
            for roledefinition, linkroleUri in linkroleUris:
                linkRelationshipSet = self.modelXbrl.relationshipSet(arcrole, linkroleUri, linkqname, arcqname)
                for rootConcept in linkRelationshipSet.rootConcepts:
                    self.treeDepth(rootConcept, rootConcept, 2, arcrole, linkRelationshipSet, set())
                    
        self.addRow(heading, asHeader=True) # must do after determining tree depth
        
        if relationshipSet:
            # for each URI in definition order
            for roledefinition, linkroleUri in linkroleUris:
                attr = {"role": linkroleUri}
                self.addRow([roledefinition], treeIndent=0, colSpan=len(heading), 
                            xmlRowElementName="linkRole", xmlRowEltAttr=attr, xmlCol0skipElt=True)
                linkRelationshipSet = self.modelXbrl.relationshipSet(arcrole, linkroleUri, linkqname, arcqname)
                for rootConcept in linkRelationshipSet.rootConcepts:
                    self.viewConcept(rootConcept, rootConcept, "", self.labelrole, 1, arcrole, linkRelationshipSet, set())
Ejemplo n.º 10
0
    def view(self, arcrole, linkrole=None, linkqname=None, arcqname=None):
        # determine relationships indent depth for dimensions linkbases
        # set up treeView widget and tabbed pane
        if arcrole == XbrlConst.parentChild: # extra columns
            heading = ["Presentation Relationships", "Pref. Label", "Type", "References"]
        elif arcrole == XbrlConst.summationItem:    # add columns for calculation relationships
            heading = ["Calculation Relationships", "Weight", "Balance"]
        elif arcrole == "XBRL-dimensions":    # add columns for dimensional information
            heading = ["Dimensions Relationships", "Arcrole","CntxElt","Closed","Usable"]
        elif isinstance(arcrole, (list,tuple)) or XbrlConst.isResourceArcrole(arcrole):
            self.isResourceArcrole = True
            self.showReferences = isinstance(arcrole, _STR_BASE) and arcrole.endswith("-reference")
            heading = ["Resource Relationships", "Arcrole","Resource","ResourceRole","Language"]
        else:
            heading = [os.path.basename(arcrole).title() + " Relationships"]
        # relationship set based on linkrole parameter, to determine applicable linkroles
        relationshipSet = self.modelXbrl.relationshipSet(arcrole, linkrole, linkqname, arcqname)

        self.arcrole = arcrole
        
        if relationshipSet:
            # sort URIs by definition
            linkroleUris = []
            for linkroleUri in relationshipSet.linkRoleUris:
                modelRoleTypes = self.modelXbrl.roleTypes.get(linkroleUri)
                if modelRoleTypes:
                    roledefinition = (modelRoleTypes[0].genLabel(lang=self.lang, strip=True) or modelRoleTypes[0].definition or linkroleUri)                    
                else:
                    roledefinition = linkroleUri
                linkroleUris.append((roledefinition, linkroleUri))
            linkroleUris.sort()
    
            for roledefinition, linkroleUri in linkroleUris:
                linkRelationshipSet = self.modelXbrl.relationshipSet(arcrole, linkroleUri, linkqname, arcqname)
                for rootConcept in linkRelationshipSet.rootConcepts:
                    self.treeDepth(rootConcept, rootConcept, 2, arcrole, linkRelationshipSet, set())
                    
        self.addRow(heading, asHeader=True) # must do after determining tree depth
        
        if relationshipSet:
            # for each URI in definition order
            for roledefinition, linkroleUri in linkroleUris:
                attr = {"role": linkroleUri}
                self.addRow([roledefinition], treeIndent=0, colSpan=len(heading), 
                            xmlRowElementName="linkRole", xmlRowEltAttr=attr, xmlCol0skipElt=True)
                linkRelationshipSet = self.modelXbrl.relationshipSet(arcrole, linkroleUri, linkqname, arcqname)
                for rootConcept in linkRelationshipSet.rootConcepts:
                    self.viewConcept(rootConcept, rootConcept, "", self.labelrole, 1, arcrole, linkRelationshipSet, set())
Ejemplo n.º 11
0
 def __init__(self,
              modelXbrl,
              tabWin,
              arcrole,
              linkrole=None,
              linkqname=None,
              arcqname=None,
              lang=None,
              treeColHdr=None):
     super().__init__(modelXbrl, tabWin,
                      XbrlConst.baseSetArcroleLabel(arcrole)[1:], True,
                      lang)
     self.arcrole = arcrole
     self.linkrole = linkrole
     self.linkqname = linkqname
     self.arcqname = arcqname
     self.treeColHdr = treeColHdr
Ejemplo n.º 12
0
 def __init__(self, modelXbrl, tabWin, 
              arcrole, linkrole=None, linkqname=None, arcqname=None, lang=None, 
              treeColHdr=None, showLinkroles=True, showRelationships=True, showColumns=True,
              expandAll=False):
     if isinstance(arcrole, (list,tuple)):
         tabName = arcrole[0]
     else:
         tabName = XbrlConst.baseSetArcroleLabel(arcrole)[1:]
     super(ViewRelationshipSet, self).__init__(modelXbrl, tabWin, tabName, True, lang)
     self.arcrole = arcrole
     self.linkrole = linkrole
     self.linkqname = linkqname
     self.arcqname = arcqname
     self.treeColHdr = treeColHdr
     self.showLinkroles = showLinkroles
     self.showRelationships = showRelationships
     self.showColumns = showColumns
     self.expandAllOnFirstDisplay = expandAll
     self.isResourceArcrole = False
Ejemplo n.º 13
0
 def insertResources(self):
     self.showStatus("insert resources")
     # deduplicate resources (may be on multiple arcs)
     # note that lxml has no column numbers, use objectIndex as pseudo-column number
     uniqueResources = dict(((self.documentIds[resource.modelDocument.uri],
                              resource.sourceline,
                              resource.objectIndex), resource)
                            for arcrole in (XbrlConst.conceptLabel, XbrlConst.conceptReference)
                            for rel in self.modelXbrl.relationshipSet(arcrole).modelRelationships
                            if rel.fromModelObject is not None and rel.toModelObject is not None
                            for resource in (rel.fromModelObject, rel.toModelObject)
                            if isinstance(resource, ModelResource))
     table = self.getTable('resource', 'resource_id', 
                           ('role_uri_id', 'qname_id', 'document_id', 'document_line_number', 'document_column_number'), 
                           ('document_id', 'document_line_number', 'document_column_number'), 
                           tuple((self.uriId[resource.role],
                                  self.qnameId[resource.qname],
                                  self.documentIds[resource.modelDocument.uri],
                                  resource.sourceline,
                                  resource.objectIndex)
                                 for resource in uniqueResources.values()),
                           checkIfExisting=True)
     self.resourceId = dict(((docId, line, offset), id)
                            for id, docId, line, offset in table)
     
     self.showStatus("insert labels")
     table = self.getTable('label_resource', 'resource_id', 
                           ('resource_id', 'label', 'xml_lang'), 
                           ('resource_id',), 
                           tuple((self.resourceId[self.documentIds[resource.modelDocument.uri],
                                                  resource.sourceline,
                                                  resource.objectIndex],
                                  resource.textValue,
                                  resource.xmlLang)
                                 for arcrole in (XbrlConst.conceptLabel, XbrlConst.conceptReference)
                                 for rel in self.modelXbrl.relationshipSet(arcrole).modelRelationships
                                 if rel.fromModelObject is not None and rel.toModelObject is not None
                                 for resource in (rel.fromModelObject, rel.toModelObject)
                                 if isinstance(resource, ModelResource) and XbrlConst.isLabelRole(resource.role)),
                           checkIfExisting=True)
Ejemplo n.º 14
0
    def validate(self, modelXbrl, parameters=None):
        self.parameters = parameters
        self.NCnamePattern = re.compile(
            "^[_A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]"
            r"[_\-\."
            "\xB7A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040]*$"
        )
        self.precisionPattern = re.compile("^([0-9]+|INF)$")
        self.decimalsPattern = re.compile("^(-?[0-9]+|INF)$")
        self.isoCurrencyPattern = re.compile(r"^[A-Z]{3}$")
        self.modelXbrl = modelXbrl
        self.validateDisclosureSystem = modelXbrl.modelManager.validateDisclosureSystem
        self.disclosureSystem = modelXbrl.modelManager.disclosureSystem
        self.validateEFM = self.validateDisclosureSystem and self.disclosureSystem.EFM
        self.validateGFM = self.validateDisclosureSystem and self.disclosureSystem.GFM
        self.validateEFMorGFM = self.validateDisclosureSystem and self.disclosureSystem.EFMorGFM
        self.validateHMRC = self.validateDisclosureSystem and self.disclosureSystem.HMRC
        self.validateSBRNL = self.validateDisclosureSystem and self.disclosureSystem.SBRNL
        self.validateXmlLang = self.validateDisclosureSystem and self.disclosureSystem.xmlLangPattern
        self.validateCalcLB = modelXbrl.modelManager.validateCalcLB
        self.validateInferDecimals = modelXbrl.modelManager.validateInferDecimals

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

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

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

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

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

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

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

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

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

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

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

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

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

        if modelXbrl.hasFormulae:
            ValidateFormula.validate(self)

        modelXbrl.modelManager.showStatus(_("ready"), 2000)
Ejemplo n.º 15
0
    def validate(self, modelVersReport):
        self.modelVersReport = modelVersReport
        versReport = modelVersReport.modelDocument
        if not hasattr(versReport, "xmlDocument"):  # not parsed
            return
        for DTSname in ("fromDTS", "toDTS"):
            DTSmodelXbrl = getattr(versReport, DTSname)
            if DTSmodelXbrl is None or DTSmodelXbrl.modelDocument is None:
                self.modelVersReport.error(
                    _("{0} is missing or not loaded").format(DTSname), "err",
                    "vere:invalidDTSIdentifier")
            else:
                # validate DTS
                ValidateXbrl.ValidateXbrl(DTSmodelXbrl).validate(DTSmodelXbrl)
                if len(DTSmodelXbrl.errors) > 0:
                    self.modelVersReport.error(
                        _("{0} {1} has errors: {2}").format(
                            DTSname, DTSmodelXbrl.modelDocument.basename,
                            DTSmodelXbrl.errors), "err",
                        "vere:invalidDTSIdentifier")
        # validate linkbases
        ValidateXbrl.ValidateXbrl(
            self.modelVersReport).validate(modelVersReport)

        versReportElt = versReport.xmlRootElement
        # check actions
        for assignmentRef in versReportElt.getElementsByTagNameNS(
                XbrlConst.ver, "assignmentRef"):
            ref = assignmentRef.getAttribute("ref")
            if ref not in versReport.idObjects or \
               not isinstance(versReport.idObjects[ref], ModelVersObject.ModelAssignment):
                self.modelVersReport.error(
                    _("AssignmentRef {0} does not reference an assignment").
                    format(ref), "err", "vere:invalidAssignmentRef")

        # check namespace renames
        for NSrename in versReport.namespaceRenameFrom.values():
            if NSrename.fromURI not in versReport.fromDTS.namespaceDocs:
                self.modelVersReport.error(
                    _("NamespaceRename fromURI {0} does not reference a schema in fromDTS"
                      ).format(NSrename.fromURI), "err",
                    "vere:invalidNamespaceMapping")
            if NSrename.toURI not in versReport.toDTS.namespaceDocs:
                self.modelVersReport.error(
                    _("NamespaceRename toURI {0} does not reference a schema in toDTS"
                      ).format(NSrename.toURI), "err",
                    "vere:invalidNamespaceMapping")

        # check role changes
        for roleChange in versReport.roleChanges.values():
            if roleChange.fromURI not in versReport.fromDTS.roleTypes:
                self.modelVersReport.error(
                    _("RoleChange fromURI {0} does not reference a roleType in fromDTS"
                      ).format(roleChange.fromURI), "err",
                    "vere:invalidRoleChange")
            if roleChange.toURI not in versReport.toDTS.roleTypes:
                self.modelVersReport.error(
                    _("RoleChange toURI {0} does not reference a roleType in toDTS"
                      ).format(roleChange.toURI), "err",
                    "vere:invalidRoleChange")

        # check reportRefs
        # check actions
        for reportRef in versReportElt.getElementsByTagNameNS(
                XbrlConst.ver, "reportRef"):
            xlinkType = reportRef.getAttributeNS(XbrlConst.xlink, "type")
            if xlinkType != "simple":
                self.modelVersReport.error(
                    _("ReportRef xlink:type {0} must be \"simple\"").format(
                        xlinkType), "err", "vere:invalidXlinkType")
            # if existing it must be valid
            href = reportRef.getAttributeNS(XbrlConst.xlink, "href")
            # TBD

            if not reportRef.hasAttributeNS(XbrlConst.xlink, "arcrole"):
                self.modelVersReport.error(
                    _("ReportRef xlink:arcrole is missing"), "err",
                    "vere:missingXlinkArcrole")
            else:
                arcrole = reportRef.getAttributeNS(XbrlConst.xlink, "arcrole")
                if arcrole != "http://xbrl.org/arcrole/2010/versioning/related-report":
                    self.modelVersReport.error(
                        _("ReportRef xlink:arcrole {0} is invalid").format(
                            arcrole), "err", "vere:invalidXlinkArcrole")

        if versReport.fromDTS and versReport.toDTS:
            # check concept changes of concept basic
            for conceptChange in versReport.conceptBasicChanges:
                if conceptChange.name != "conceptAdd" and \
                   (conceptChange.fromConcept is None or \
                    conceptChange.fromConcept.qname not in versReport.fromDTS.qnameConcepts):
                    self.modelVersReport.error(
                        _("{0} fromConcept {1} does not reference a concept in fromDTS"
                          ).format(conceptChange.name,
                                   conceptChange.fromConceptQname), "err",
                        "vercbe:invalidConceptReference")
                if conceptChange.name != "conceptDelete" and \
                   (conceptChange.toConcept is None or \
                    conceptChange.toConcept.qname not in versReport.toDTS.qnameConcepts):
                    self.modelVersReport.error(
                        _("{0} toConcept {1} does not reference a concept in toDTS"
                          ).format(conceptChange.name,
                                   conceptChange.toConceptQname), "err",
                        "vercbe:invalidConceptReference")

            # check concept changes of concept extended
            for conceptChange in versReport.conceptExtendedChanges:
                fromConcept = conceptChange.fromConcept
                toConcept = conceptChange.toConcept
                fromResource = conceptChange.fromResource
                toResource = conceptChange.toResource
                # fromConcept checks
                if not conceptChange.name.endswith("Add"):
                    if not fromConcept:
                        self.modelVersReport.error(
                            _("{0} {1} fromConcept {2} does not reference a concept in fromDTS"
                              ).format(conceptChange.actionId,
                                       conceptChange.name,
                                       conceptChange.fromConceptQname), "err",
                            "vercbe:invalidConceptReference")
                    # tuple check
                    elif "Child" in conceptChange.name and \
                        not versReport.fromDTS.qnameConcepts[fromConcept.qname] \
                            .isTuple:
                        self.modelVersReport.error(
                            _("{0} {1} fromConcept {2} must be defined as a tuple"
                              ).format(conceptChange.actionId,
                                       conceptChange.name,
                                       conceptChange.fromConceptQname), "err",
                            "vercbe:invalidConceptReference")
                    # resource check
                    elif "Label" in conceptChange.name:
                        if not fromResource:
                            self.modelVersReport.error(
                                _("{0} {1} fromResource {2} does not reference a resource in fromDTS"
                                  ).format(conceptChange.actionId,
                                           conceptChange.name,
                                           conceptChange.fromResourceValue),
                                "err",
                                "vercee:invalidContentResourceIdentifier")
                        else:
                            relationship = fromConcept.relationshipToResource(
                                fromResource, XbrlConst.conceptLabel)
                            if relationship:
                                if relationship.qname != XbrlConst.qnLinkLabelArc or \
                                   relationship.parentQname != XbrlConst.qnLinkLabelLink or \
                                   fromResource.qname != XbrlConst.qnLinkLabel:
                                    self.modelVersReport.error(
                                        _("{0} {1} fromResource {2} for {3} in fromDTS does not have expected link, arc, or label elements"
                                          ).format(
                                              conceptChange.actionId,
                                              conceptChange.name,
                                              conceptChange.fromResourceValue,
                                              conceptChange.fromConceptQname),
                                        "err",
                                        "vercee:invalidConceptLabelIdentifier")
                            else:
                                relationship = fromConcept.relationshipToResource(
                                    fromResource, XbrlConst.elementLabel)
                                if relationship:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       fromResource.qname != XbrlConst.qnGenLabel:
                                        self.modelVersReport.error(
                                            _("{0} {1} fromResource {2} for {3} in fromDTS does not have expected link, arc, or label elements"
                                              ).format(
                                                  conceptChange.actionId,
                                                  conceptChange.name,
                                                  conceptChange.
                                                  fromResourceValue,
                                                  conceptChange.
                                                  fromConceptQname), "err",
                                            "vercee:invalidConceptLabelIdentifier"
                                        )
                                else:
                                    self.modelVersReport.error(
                                        _("{0} {1} fromResource {2} does not have a label relationship to {3} in fromDTS"
                                          ).format(
                                              conceptChange.actionId,
                                              conceptChange.name,
                                              conceptChange.fromResourceValue,
                                              conceptChange.fromConceptQname),
                                        "err",
                                        "vercee:invalidContentResourceIdentifier"
                                    )
                    elif "Reference" in conceptChange.name:
                        if not fromResource:
                            self.modelVersReport.error(
                                _("{0} {1} fromResource {2} does not reference a resource in fromDTS"
                                  ).format(conceptChange.actionId,
                                           conceptChange.name,
                                           conceptChange.fromResourceValue),
                                "err",
                                "vercee:invalidContentResourceIdentifier")
                        else:
                            relationship = fromConcept.relationshipToResource(
                                fromResource, XbrlConst.conceptReference)
                            if relationship:
                                if relationship.qname != XbrlConst.qnLinkReferenceArc or \
                                   relationship.parentQname != XbrlConst.qnLinkReferenceLink or \
                                   fromResource.qname != XbrlConst.qnLinkReference:
                                    self.modelVersReport.error(
                                        _("{0} {1} fromResource {2} for {3} in fromDTS does not have expected link, arc, or label elements"
                                          ).format(
                                              conceptChange.actionId,
                                              conceptChange.name,
                                              conceptChange.fromResourceValue,
                                              conceptChange.fromConceptQname),
                                        "err",
                                        "vercee:invalidConceptReferenceIdentifier"
                                    )
                            else:
                                relationship = fromConcept.relationshipToResource(
                                    fromResource, XbrlConst.elementReference)
                                if relationship:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       fromResource.qname != XbrlConst.qnGenReference:
                                        self.modelVersReport.error(
                                            _("{0} {1} fromResource {2} for {3} in fromDTS does not have expected link, arc, or label elements"
                                              ).format(
                                                  conceptChange.actionId,
                                                  conceptChange.name,
                                                  conceptChange.
                                                  fromResourceValue,
                                                  conceptChange.
                                                  fromConceptQname), "err",
                                            "vercee:invalidConceptReferenceIdentifier"
                                        )
                                else:
                                    self.modelVersReport.error(
                                        _("{0} {1} fromResource {2} does not have a reference relationship to {3} in fromDTS"
                                          ).format(
                                              conceptChange.actionId,
                                              conceptChange.name,
                                              conceptChange.fromResourceValue,
                                              conceptChange.fromConceptQname),
                                        "err",
                                        "vercee:invalidContentResourceIdentifier"
                                    )

                # toConcept checks
                if not conceptChange.name.endswith("Delete"):
                    if not toConcept:
                        self.modelVersReport.error(
                            _("{0} {1} toConcept {2} does not reference a concept in toDTS"
                              ).format(conceptChange.actionId,
                                       conceptChange.name,
                                       conceptChange.toConceptQname), "err",
                            "vercbe:invalidConceptReference")
                    # tuple check
                    elif "Child" in conceptChange.name and \
                        not versReport.toDTS.qnameConcepts[toConcept.qname] \
                            .isTuple:
                        self.modelVersReport.error(
                            _("{0} {1} toConcept {2} must be defined as a tuple"
                              ).format(conceptChange.actionId,
                                       conceptChange.name,
                                       conceptChange.toConceptQname), "err",
                            "vercbe:invalidConceptReference")
                    # resource check
                    elif "Label" in conceptChange.name:
                        if not toResource:
                            self.modelVersReport.error(
                                _("{0} {1} toResource {2} does not reference a resource in toDTS"
                                  ).format(conceptChange.actionId,
                                           conceptChange.name,
                                           conceptChange.toResourceValue),
                                "err",
                                "vercee:invalidContentResourceIdentifier")
                        else:
                            relationship = toConcept.relationshipToResource(
                                toResource, XbrlConst.conceptLabel)
                            if relationship:
                                if relationship.qname != XbrlConst.qnLinkLabelArc or \
                                   relationship.parentQname != XbrlConst.qnLinkLabelLink or \
                                   toResource.qname != XbrlConst.qnLinkLabel:
                                    self.modelVersReport.error(
                                        _("{0} {1} toResource {2} for {3} in toDTS does not have expected link, arc, or label elements"
                                          ).format(
                                              conceptChange.actionId,
                                              conceptChange.name,
                                              conceptChange.toResourceValue,
                                              conceptChange.toConceptQname),
                                        "err",
                                        "vercee:invalidConceptLabelIdentifier")
                            else:
                                relationship = toConcept.relationshipToResource(
                                    toResource, XbrlConst.elementLabel)
                                if relationship:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       toResource.qname != XbrlConst.qnGenLabel:
                                        self.modelVersReport.error(
                                            _("{0} {1} toResource {2} for {3} in toDTS does not have expected link, arc, or label elements"
                                              ).
                                            format(
                                                conceptChange.actionId,
                                                conceptChange.name,
                                                conceptChange.toResourceValue,
                                                conceptChange.toConceptQname),
                                            "err",
                                            "vercee:invalidConceptLabelIdentifier"
                                        )
                                else:
                                    self.modelVersReport.error(
                                        _("{0} {1} toResource {2} does not have a label relationship to {3} in toDTS"
                                          ).format(
                                              conceptChange.actionId,
                                              conceptChange.name,
                                              conceptChange.toResourceValue,
                                              conceptChange.toConceptQname),
                                        "err",
                                        "vercee:invalidContentResourceIdentifier"
                                    )
                    elif "Reference" in conceptChange.name:
                        if not toResource:
                            self.modelVersReport.error(
                                _("{0} {1} toResource {2} does not reference a resource in toDTS"
                                  ).format(conceptChange.actionId,
                                           conceptChange.name,
                                           conceptChange.toResourceValue),
                                "err",
                                "vercee:invalidContentResourceIdentifier")
                        else:
                            relationship = toConcept.relationshipToResource(
                                toResource, XbrlConst.conceptReference)
                            if relationship:
                                if relationship.qname != XbrlConst.qnLinkReferenceArc or \
                                   relationship.parentQname != XbrlConst.qnLinkReferenceLink or \
                                   toResource.qname != XbrlConst.qnLinkReference:
                                    self.modelVersReport.error(
                                        _("{0} {1} toResource {2} for {3} in toDTS does not have expected link, arc, or label elements"
                                          ).format(
                                              conceptChange.actionId,
                                              conceptChange.name,
                                              conceptChange.toResourceValue,
                                              conceptChange.toConceptQname),
                                        "err",
                                        "vercee:invalidConceptReferenceIdentifier"
                                    )
                            else:
                                relationship = toConcept.relationshipToResource(
                                    toResource, XbrlConst.elementReference)
                                if relationship:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       toResource.qname != XbrlConst.qnGenReference:
                                        self.modelVersReport.error(
                                            _("{0} {1} toResource {2} for {3} in toDTS does not have expected link, arc, or label elements"
                                              ).
                                            format(
                                                conceptChange.actionId,
                                                conceptChange.name,
                                                conceptChange.toResourceValue,
                                                conceptChange.toConceptQname),
                                            "err",
                                            "vercee:invalidConceptReferenceIdentifier"
                                        )
                                else:
                                    self.modelVersReport.error(
                                        _("{0} {1} toResource {2} does not have a reference relationship to {3} in toDTS"
                                          ).format(
                                              conceptChange.actionId,
                                              conceptChange.name,
                                              conceptChange.toResourceValue,
                                              conceptChange.toConceptQname),
                                        "err",
                                        "vercee:invalidContentResourceIdentifier"
                                    )

                # check concept correspondence
                if fromConcept and toConcept:
                    if versReport.toDTSqname(fromConcept.qname) != toConcept.qname and \
                       versReport.equivalentConcepts.get(fromConcept.qname) != toConcept.qname and \
                       toConcept.qname not in versReport.relatedConcepts.get(fromConcept.qname,[]):
                        self.modelVersReport.error(
                            _("{0} {1} fromConcept {2} and toConcept {3} must be equivalent or related"
                              ).format(conceptChange.actionId,
                                       conceptChange.name,
                                       conceptChange.fromConceptQname,
                                       conceptChange.toConceptQname), "err",
                            "vercee:invalidConceptCorrespondence")

                # custom attribute events
                if conceptChange.name.startswith("conceptAttribute"):
                    try:
                        for attr in conceptAttributeEventAttributes[
                                conceptChange.name]:
                            customAttributeQname = conceptChange.customAttributeQname(
                                attr)
                            if not customAttributeQname or customAttributeQname.namespaceURI is None:
                                self.modelVersReport.error(
                                    _("{0} {1} {2} {3} does not have a namespace"
                                      ).format(conceptChange.actionId,
                                               conceptChange.name, attr,
                                               customAttributeQname), "err",
                                    "vercee:invalidAttributeChange")
                            elif customAttributeQname.namespaceURI in (
                                    XbrlConst.xbrli, XbrlConst.xsd):
                                self.modelVersReport.error(
                                    _("{0} {1} {2} {3} has an invalid namespace"
                                      ).format(conceptChange.actionId,
                                               conceptChange.name, attr,
                                               customAttributeQname), "err",
                                    "vercee:illegalCustomAttributeEvent")
                    except KeyError:
                        self.modelVersReport.error(
                            _("{0} {1} event is not recognized").format(
                                conceptChange.actionId, conceptChange.name),
                            "info", "arelle:eventNotRecognized")

            # check relationship set changes
            for relSetChange in versReport.relationshipSetChanges:
                for relationshipSet, name in (
                    (relSetChange.fromRelationshipSet, "fromRelationshipSet"),
                    (relSetChange.toRelationshipSet, "toRelationshipSet")):
                    if relationshipSet:
                        relationshipSetValid = True
                        if relationshipSet.link and relationshipSet.link not in relationshipSet.dts.qnameConcepts:
                            self.modelVersReport.error(
                                _("{0} link {1} does not reference an element in its DTS"
                                  ).format(relSetChange.name, name,
                                           relationshipSet.link), "err",
                                "verrelse:invalidLinkElementReference")
                            relationshipSetValid = False
                        if relationshipSet.arc and relationshipSet.arc not in relationshipSet.dts.qnameConcepts:
                            self.modelVersReport.error(
                                _("{0} arc {1} does not reference an element in its DTS"
                                  ).format(relSetChange.name, name,
                                           relationshipSet.link), "err",
                                "verrelse:invalidArcElementReference")
                            relationshipSetValid = False
                        if relationshipSet.linkrole and not (
                                XbrlConst.isStandardRole(
                                    relationshipSet.linkrole)
                                or relationshipSet.linkrole
                                in relationshipSet.dts.roleTypes):
                            self.modelVersReport.error(
                                _("{0} linkrole {1} does not reference an linkrole in its DTS"
                                  ).format(relSetChange.name, name,
                                           relationshipSet.linkrole), "err",
                                "verrelse:invalidLinkrole")
                            relationshipSetValid = False
                        if relationshipSet.arcrole and not (
                                XbrlConst.isStandardArcrole(
                                    relationshipSet.arcrole)
                                or relationshipSet.arcrole
                                in relationshipSet.dts.arcroleTypes):
                            self.modelVersReport.error(
                                _("{0} arcrole {1} does not reference an arcrole in its DTS"
                                  ).format(relSetChange.name, name,
                                           relationshipSet.linkrole), "err",
                                "verrelse:invalidArcrole")
                            relationshipSetValid = False
                        for relationship in relationshipSet.relationships:
                            # fromConcept checks
                            if not relationship.fromConcept:
                                self.modelVersReport.error(
                                    _("{0} {1} relationship fromConcept {2} does not reference a concept in its DTS"
                                      ).format(relSetChange.name, name,
                                               relationship.fromName), "err",
                                    "verrelse:invalidConceptReference")
                                relationshipSetValid = False
                            if relationship.toName and not relationship.toConcept:
                                self.modelVersReport.error(
                                    _("{0} {1} relationship toConcept {2} does not reference a concept in its DTS"
                                      ).format(relSetChange.name, name,
                                               relationship.toName), "err",
                                    "verrelse:invalidConceptReference")
                                relationshipSetValid = False
                            if relationshipSetValid:  # test that relations exist
                                if relationship.fromRelationship is None:
                                    if relationship.toName:
                                        self.modelVersReport.error(
                                            _("{0} {1} no relationship found from toConcept {2} to {3} in its DTS"
                                              ).format(relSetChange.name, name,
                                                       relationship.fromName,
                                                       relationship.toName),
                                            "err",
                                            "verrelse:invalidRelationshipReference"
                                        )
                                    else:
                                        self.modelVersReport.error(
                                            _("{0} {1} no relationship found from toConcept {2} in its DTS"
                                              ).format(relSetChange.name, name,
                                                       relationship.fromName),
                                            "err",
                                            "verrelse:invalidRelationshipReference"
                                        )
            '''
Ejemplo n.º 16
0
def init(modelXbrl):
    # setup modelXbrl for rendering evaluation

    # dimension defaults required in advance of validation
    from arelle import ValidateXbrlDimensions, ValidateFormula, ModelDocument
    ValidateXbrlDimensions.loadDimensionDefaults(modelXbrl)
    
    hasXbrlTables = False
    
    # validate table linkbase dimensions
    for baseSetKey in modelXbrl.baseSets.keys():
        arcrole, ELR, linkqname, arcqname = baseSetKey
        if ELR and linkqname and arcqname and XbrlConst.isTableRenderingArcrole(arcrole):
            ValidateFormula.checkBaseSet(modelXbrl, arcrole, ELR, modelXbrl.relationshipSet(arcrole,ELR,linkqname,arcqname))
            if arcrole in (XbrlConst.tableBreakdown, XbrlConst.tableBreakdownMMDD, XbrlConst.tableBreakdown201305, XbrlConst.tableBreakdown201301, XbrlConst.tableAxis2011):
                hasXbrlTables = True

    # provide context for view
    if modelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE:
        instance = None # use instance of the entry pont
    else: # need dummy instance
        instance = ModelDocument.create(modelXbrl, ModelDocument.Type.INSTANCE, 
                                        "dummy.xml",  # fake URI and fake schemaRef 
                                        ("http://www.xbrl.org/2003/xbrl-instance-2003-12-31.xsd",))
        
    if hasXbrlTables:
        # formula processor is needed for 2011 XBRL tables but not for 2010 Eurofiling tables
        modelXbrl.rendrCntx = XPathContext.create(modelXbrl, instance)
        
        modelXbrl.profileStat(None)
        
        # setup fresh parameters from formula options
        modelXbrl.parameters = modelXbrl.modelManager.formulaOptions.typedParameters()
        
        # validate parameters and custom function signatures
        ValidateFormula.validate(modelXbrl, xpathContext=modelXbrl.rendrCntx, parametersOnly=True, statusMsg=_("compiling rendering tables"))
        
        # deprecated as of 2013-05-17
        # check and extract message expressions into compilable programs
        for msgArcrole in (XbrlConst.tableDefinitionNodeMessage201301, XbrlConst.tableDefinitionNodeSelectionMessage201301,
                           XbrlConst.tableAxisMessage2011, XbrlConst.tableAxisSelectionMessage2011):
            for msgRel in modelXbrl.relationshipSet(msgArcrole).modelRelationships:
                ValidateFormula.checkMessageExpressions(modelXbrl, msgRel.toModelObject)
                
        # compile and validate tables
        for modelTable in modelXbrl.modelRenderingTables:
            modelTable.fromInstanceQnames = None # required if referred to by variables scope chaining
            modelTable.compile()

            hasNsWithAspectModel = modelTable.namespaceURI in (XbrlConst.euRend, XbrlConst.table2011, XbrlConst.table201301, XbrlConst.table201305) 
        
            # check aspectModel  (attribute removed 2013-06, now always dimensional)
            if modelTable.aspectModel not in ("non-dimensional", "dimensional") and hasNsWithAspectModel:
                modelXbrl.error("xbrlte:unknownAspectModel",
                    _("Table %(xlinkLabel)s, aspect model %(aspectModel)s not recognized"),
                    modelObject=modelTable, xlinkLabel=modelTable.xlinkLabel, aspectModel=modelTable.aspectModel)
            else:
                modelTable.priorAspectAxisDisposition = {}
                # check ordinate aspects against aspectModel
                oppositeAspectModel = (_DICT_SET({'dimensional','non-dimensional'}) - _DICT_SET({modelTable.aspectModel})).pop()
                if hasNsWithAspectModel:
                    uncoverableAspects = aspectModels[oppositeAspectModel] - aspectModels[modelTable.aspectModel]
                else:
                    uncoverableAspects = ()
                aspectsCovered = set()
                for tblAxisRel in modelXbrl.relationshipSet((XbrlConst.tableBreakdown, XbrlConst.tableBreakdownMMDD, XbrlConst.tableBreakdown201305, XbrlConst.tableBreakdown201301,XbrlConst.tableAxis2011)).fromModelObject(modelTable):
                    breakdownAspectsCovered = set()
                    hasCoveredAspect = checkBreakdownDefinitionNode(modelXbrl, modelTable, tblAxisRel, tblAxisRel.axisDisposition, uncoverableAspects, breakdownAspectsCovered)
                    ''' removed 2013-10
                    if not hasCoveredAspect:
                        definitionNode = tblAxisRel.toModelObject
                        modelXbrl.error("xbrlte:breakdownDefinesNoAspects",
                            _("Breakdown %(xlinkLabel)s has no participating aspects"),
                            modelObject=(modelTable,definitionNode), xlinkLabel=definitionNode.xlinkLabel, axis=definitionNode.localName)
                    '''
                    aspectsCovered |= breakdownAspectsCovered
                    checkBreakdownLeafNodeAspects(modelXbrl, modelTable, tblAxisRel, set(), breakdownAspectsCovered)
                if Aspect.CONCEPT not in aspectsCovered and not hasNsWithAspectModel:
                    modelXbrl.error("xbrlte:tableMissingConceptAspect",
                        _("Table %(xlinkLabel)s does not include the concept aspect as one of its participating aspects"),
                        modelObject=modelTable, xlinkLabel=modelTable.xlinkLabel)
                del modelTable.priorAspectAxisDisposition
                # check for table-parameter name clash
                parameterNames = {}
                for tblParamRel in modelXbrl.relationshipSet((XbrlConst.tableParameter, XbrlConst.tableParameterMMDD)).fromModelObject(modelTable):
                    parameterName = tblParamRel.variableQname
                    if parameterName in parameterNames:
                        modelXbrl.error("xbrlte:tableParameterNameClash ",
                            _("Table %(xlinkLabel)s has parameter name clash for variable %(name)s"),
                            modelObject=(modelTable,tblParamRel,parameterNames[parameterName]), xlinkLabel=modelTable.xlinkLabel, name=parameterName)
                    else:
                        parameterNames[parameterName] = tblParamRel
    
        modelXbrl.profileStat(_("compileTables"))
Ejemplo n.º 17
0
    def validate(self, modelVersReport):
        self.modelVersReport = modelVersReport
        versReport = modelVersReport.modelDocument
        if not hasattr(versReport, "xmlDocument"): # not parsed
            return
        for DTSname in ("fromDTS", "toDTS"):
            DTSmodelXbrl = getattr(versReport, DTSname)
            if DTSmodelXbrl is None or DTSmodelXbrl.modelDocument is None:
                self.modelVersReport.error("vere:invalidDTSIdentifier",
                    _("%(dts)s is missing or not loaded"),
                    modelObject=self, dts=DTSname)
            else:
                # validate DTS
                ValidateXbrl.ValidateXbrl(DTSmodelXbrl).validate(DTSmodelXbrl)
                if len(DTSmodelXbrl.errors) > 0:
                    self.modelVersReport.error("vere:invalidDTSIdentifier",
                        _("%(dts) has errors: %(error)s"),
                        modelObject=DTSmodelXbrl.modelDocument, dts=DTSname, error=DTSmodelXbrl.errors)
        # validate linkbases
        ValidateXbrl.ValidateXbrl(self.modelVersReport).validate(modelVersReport)

        versReportElt = versReport.xmlRootElement
        # check actions
        for assignmentRef in versReportElt.iterdescendants(tag="{http://xbrl.org/2010/versioning-base}assignmentRef"):
            ref = assignmentRef.get("ref")
            if ref not in versReport.idObjects or \
               not isinstance(versReport.idObjects[ref], ModelVersObject.ModelAssignment):
                    self.modelVersReport.error("vere:invalidAssignmentRef",
                        _("AssignmentRef %(assignmentRef)s does not reference an assignment"),
                        modelObject=assignmentRef, assignmentRef=ref)
                    
        # check namespace renames
        for NSrename in versReport.namespaceRenameFrom.values():
            if NSrename.fromURI not in versReport.fromDTS.namespaceDocs:
                self.modelVersReport.error("vere:invalidNamespaceMapping",
                    _("NamespaceRename fromURI %(uri)s does not reference a schema in fromDTS"),
                    modelObject=self, uri=NSrename.fromURI)
            if NSrename.toURI not in versReport.toDTS.namespaceDocs:
                self.modelVersReport.error("vere:invalidNamespaceMapping",
                    _("NamespaceRename toURI %(uri)s does not reference a schema in toDTS"),
                    modelObject=self, uri=NSrename.toURI)
                
        # check role changes
        for roleChange in versReport.roleChanges.values():
            if roleChange.fromURI not in versReport.fromDTS.roleTypes:
                self.modelVersReport.error("vere:invalidRoleChange",
                    _("RoleChange fromURI %(uri)s does not reference a roleType in fromDTS"),
                    modelObject=self, uri=roleChange.fromURI)
            if roleChange.toURI not in versReport.toDTS.roleTypes:
                self.modelVersReport.error("vere:invalidRoleChange",
                    _("RoleChange toURI %(uri)s does not reference a roleType in toDTS"),
                    modelObject=self, uri=roleChange.toURI)
                
        # check reportRefs
        # check actions
        for reportRef in versReportElt.iterdescendants(tag="{http://xbrl.org/2010/versioning-base}reportRef"):
            xlinkType = reportRef.get("{http://www.w3.org/1999/xlink}type")
            if xlinkType != "simple":
                self.modelVersReport.error("vere:invalidXlinkType",
                    _("ReportRef xlink:type %(xlinkType)s must be \"simple\""),
                    modelObject=reportRef, xlinkType=xlinkType)
            # if existing it must be valid
            href = reportRef.get("{http://www.w3.org/1999/xlink}href")
            # TBD
            
            arcrole = reportRef.get("{http://www.w3.org/1999/xlink}arcrole")
            if arcrole is None:
                self.modelVersReport.error("vere:missingXlinkArcrole",
                    _("ReportRef xlink:arcrole is missing"),
                    modelObject=reportRef)
            else:
                if arcrole != "http://xbrl.org/arcrole/2010/versioning/related-report":
                    self.modelVersReport.error("vere:invalidXlinkArcrole",
                        _("ReportRef xlink:arcrole %(arcrole)s is invalid"),
                        modelObject=reportRef, arcrole=arcrole)
            
        if versReport.fromDTS and versReport.toDTS:
            # check concept changes of concept basic
            for conceptChange in versReport.conceptBasicChanges:
                if conceptChange.name != "conceptAdd" and \
                   (conceptChange.fromConcept is None or \
                    conceptChange.fromConcept.qname not in versReport.fromDTS.qnameConcepts):
                    self.modelVersReport.error("vercbe:invalidConceptReference",
                        _("%(event)s fromConcept %(concept)s does not reference a concept in fromDTS"),
                        modelObject=conceptChange, event=conceptChange.name, concept=conceptChange.fromConceptQname) 
                if conceptChange.name != "conceptDelete" and \
                   (conceptChange.toConcept is None or \
                    conceptChange.toConcept.qname not in versReport.toDTS.qnameConcepts):
                    self.modelVersReport.error("vercbe:invalidConceptReference",
                        _("%(event)s toConcept %(concept)s does not reference a concept in toDTS"),
                        modelObject=conceptChange, event=conceptChange.name, concept=conceptChange.toConceptQname) 
                    
            # check concept changes of concept extended
            for conceptChange in versReport.conceptExtendedChanges:
                fromConcept = conceptChange.fromConcept
                toConcept = conceptChange.toConcept
                fromResource = conceptChange.fromResource
                toResource = conceptChange.toResource
                # fromConcept checks
                if not conceptChange.name.endswith("Add"):
                    if not fromConcept is not None:
                        self.modelVersReport.error("vercbe:invalidConceptReference",
                            _("%(action)s %(event)s fromConcept %(concept)s does not reference a concept in fromDTS"),
                            modelObject=conceptChange, action=conceptChange.actionId,
                            event=conceptChange.name, concept=conceptChange.fromConceptQname) 
                    # tuple check
                    elif _("Child") in conceptChange.name and \
                        not versReport.fromDTS.qnameConcepts[fromConcept.qname] \
                            .isTuple:
                        self.modelVersReport.error("vercbe:invalidConceptReference",
                            _("%(action)s %(event)s fromConcept %(concept)s must be defined as a tuple"),
                            modelObject=conceptChange, action=conceptChange.actionId,
                            event=conceptChange.name, concept=conceptChange.fromConceptQname) 
                    # resource check
                    elif "Label" in conceptChange.name:
                        if fromResource is None:
                            self.modelVersReport.error("vercee:invalidContentResourceIdentifier",
                                _("%(action)s %(event)s fromResource %(resource)s does not reference a resource in fromDTS"),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, resource=conceptChange.fromResourceValue) 
                        else:
                            relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.conceptLabel)
                            if relationship is not None:
                                if relationship.qname != XbrlConst.qnLinkLabelArc or \
                                   relationship.parentQname != XbrlConst.qnLinkLabelLink or \
                                   fromResource.qname != XbrlConst.qnLinkLabel:
                                    self.modelVersReport.error("vercee:invalidConceptLabelIdentifier",
                                        _("%(action)s %(event)s fromResource %(resource)s for %(concept)s in fromDTS does not have expected link, arc, or label elements"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.fromResourceValue, concept=conceptChange.fromConceptQname)
                            else:
                                relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.elementLabel)
                                if relationship is not None:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       fromResource.qname != XbrlConst.qnGenLabel:
                                        self.modelVersReport.error("vercee:invalidConceptLabelIdentifier",
                                            _("%(action)s %(event)s fromResource %(resource)s for %(concept)s in fromDTS does not have expected link, arc, or label elements"),
                                            modelObject=conceptChange, action=conceptChange.actionId,
                                            event=conceptChange.name, resource=conceptChange.fromResourceValue, concept=conceptChange.fromConceptQname)
                                else:
                                    self.modelVersReport.error("vercee:invalidContentResourceIdentifier",
                                        _("%(action)s %(event)s fromResource %(resource)s does not have a label relationship to {3} in fromDTS"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.fromResourceValue)
                    elif "Reference" in conceptChange.name:
                        if fromResource is None:
                            self.modelVersReport.error("vercee:invalidContentResourceIdentifier",
                                _("%(action)s %(event)s fromResource %(resource)s does not reference a resource in fromDTS"),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, resource=conceptChange.fromResourceValue)
                        else:
                            relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.conceptReference)
                            if relationship is not None:
                                if relationship.qname != XbrlConst.qnLinkReferenceArc or \
                                   relationship.parentQname != XbrlConst.qnLinkReferenceLink or \
                                   fromResource.qname != XbrlConst.qnLinkReference:
                                    self.modelVersReport.error("vercee:invalidConceptReferenceIdentifier",
                                        _("%(action)s %(event)s fromResource %(resource)s for %(concept)s in fromDTS does not have expected link, arc, or label elements"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.fromResourceValue, concept=conceptChange.fromConceptQname)
                            else:
                                relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.elementReference)
                                if relationship is not None:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       fromResource.qname != XbrlConst.qnGenReference:
                                        self.modelVersReport.error("vercee:invalidConceptReferenceIdentifier",
                                            _("%(action)s %(event)s fromResource %(resource)s for %(concept)s  in fromDTS does not have expected link, arc, or label elements"),
                                            modelObject=conceptChange, action=conceptChange.actionId,
                                            event=conceptChange.name, resource=conceptChange.fromResourceValue, concept=conceptChange.fromConceptQname)
                                else:
                                    self.modelVersReport.error("vercee:invalidContentResourceIdentifier",
                                        _("%(action)s %(event)s fromResource %(resource)s does not have a reference relationship to %(concept)s in fromDTS"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.fromResourceValue, concept=conceptChange.fromConceptQname)
                             
                # toConcept checks
                if not conceptChange.name.endswith("Delete"):
                    if not toConcept is not None:
                        self.modelVersReport.error("vercbe:invalidConceptReference",
                            _("%(action)s %(event)s toConcept %(concept)s does not reference a concept in toDTS"),
                            modelObject=conceptChange, action=conceptChange.actionId,
                            event=conceptChange.name, concept=conceptChange.toConceptQname)
                    # tuple check
                    elif "Child" in conceptChange.name and \
                        not versReport.toDTS.qnameConcepts[toConcept.qname] \
                            .isTuple:
                        self.modelVersReport.error("vercbe:invalidConceptReference",
                            _("%(action)s %(event)s toConcept %(concept)s must be defined as a tuple"),
                            modelObject=conceptChange, action=conceptChange.actionId,
                            event=conceptChange.name, concept=conceptChange.toConceptQname)
                    # resource check
                    elif "Label" in conceptChange.name:
                        if toResource is None:
                            self.modelVersReport.error("vercee:invalidContentResourceIdentifier",
                                _("%(action)s %(event)s toResource %(resource)s for %(concept)s does not reference a resource in toDTS"),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                        else:
                            relationship = toConcept.relationshipToResource(toResource, XbrlConst.conceptLabel)
                            if relationship is not None:
                                if relationship.qname != XbrlConst.qnLinkLabelArc or \
                                   relationship.parentQname != XbrlConst.qnLinkLabelLink or \
                                   toResource.qname != XbrlConst.qnLinkLabel:
                                    self.modelVersReport.error("vercee:invalidConceptLabelIdentifier",
                                        _("%(action)s %(event)s toResource %(resource)s for %(concept)s in toDTS does not have expected link, arc, or label elements"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                            else:
                                relationship = toConcept.relationshipToResource(toResource, XbrlConst.elementLabel)
                                if relationship is not None:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       toResource.qname != XbrlConst.qnGenLabel:
                                        self.modelVersReport.error("vercee:invalidConceptLabelIdentifier",
                                            _("%(action)s %(event)s toResource %(resource)s for %(concept)s in toDTS does not have expected link, arc, or label elements"),
                                            modelObject=conceptChange, action=conceptChange.actionId,
                                            event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                                else:
                                    self.modelVersReport.error("vercee:invalidContentResourceIdentifier",
                                        _("%(action)s %(event)s toResource %(resource)s does not have a label relationship to %(concept)s in toDTS"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                    elif "Reference" in conceptChange.name:
                        if toResource is None:
                            self.modelVersReport.error("vercee:invalidContentResourceIdentifier",
                                _("%(action)s %(event)s toResource %(resource)s does not reference a resource in toDTS"),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, resource=conceptChange.toResourceValue)
                        else:
                            relationship = toConcept.relationshipToResource(toResource, XbrlConst.conceptReference)
                            if relationship is not None:
                                if relationship.qname != XbrlConst.qnLinkReferenceArc or \
                                   relationship.parentQname != XbrlConst.qnLinkReferenceLink or \
                                   toResource.qname != XbrlConst.qnLinkReference:
                                    self.modelVersReport.error("vercee:invalidConceptReferenceIdentifier",
                                        _("%(action)s %(event)s toResource %(resource)s for %(concept)s in toDTS does not have expected link, arc, or label elements"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                            else:
                                relationship = toConcept.relationshipToResource(toResource, XbrlConst.elementReference)
                                if relationship is not None:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       toResource.qname != XbrlConst.qnGenReference:
                                        self.modelVersReport.error("vercee:invalidConceptReferenceIdentifier",
                                            _("%(action)s %(event)s toResource %(resource)s for %(concept)s in toDTS does not have expected link, arc, or label elements"),
                                            modelObject=conceptChange, action=conceptChange.actionId,
                                            event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                                else:
                                    self.modelVersReport.error("vercee:invalidContentResourceIdentifier",
                                        _("%(action)s %(event)s toResource %(resource)s does not have a reference relationship to %(concept)s in toDTS"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                        
                # check concept correspondence
                if fromConcept is not None and toConcept is not None:
                    if versReport.toDTSqname(fromConcept.qname) != toConcept.qname and \
                       versReport.equivalentConcepts.get(fromConcept.qname) != toConcept.qname and \
                       toConcept.qname not in versReport.relatedConcepts.get(fromConcept.qname,[]):
                        self.modelVersReport.error("vercee:invalidConceptCorrespondence",
                            _("%(action)s %(event)s fromConcept %(conceptFrom)s and toConcept %(conceptTo)s must be equivalent or related"),
                            modelObject=conceptChange, action=conceptChange.actionId,
                            event=conceptChange.name, conceptFrom=conceptChange.fromConceptQname, conceptTo=conceptChange.toConceptQname)
    
                # custom attribute events
                if conceptChange.name.startswith("conceptAttribute"):
                    try:
                        for attr in conceptAttributeEventAttributes[conceptChange.name]:
                            customAttributeQname = conceptChange.customAttributeQname(attr)
                            if not customAttributeQname or customAttributeQname.namespaceURI is None:
                                self.modelVersReport.error("vercee:invalidAttributeChange",
                                    _("%(action)s %(event)s %(attr)s $(attrName)s does not have a namespace"),
                                    modelObject=conceptChange, action=conceptChange.actionId,
                                    attr=attr, attrName=customAttributeQname)
                            elif customAttributeQname.namespaceURI in (XbrlConst.xbrli, XbrlConst.xsd):
                                self.modelVersReport.error("vercee:illegalCustomAttributeEvent",
                                    _("%(action)s %(event)s %(attr)s $(attrName)s has an invalid namespace"),
                                    modelObject=conceptChange, action=conceptChange.actionId, event=conceptChange.name,
                                    attr=attr, attrName=customAttributeQname)
                    except KeyError:
                        self.modelVersReport.info("arelle:eventNotRecognized",
                            _("%(action)s %(event)s event is not recognized"),
                            modelObject=conceptChange, action=conceptChange.actionId, event=conceptChange.name)
    
            # check relationship set changes
            for relSetChange in versReport.relationshipSetChanges:
                for relationshipSet, name in ((relSetChange.fromRelationshipSet, "fromRelationshipSet"),
                                              (relSetChange.toRelationshipSet, "toRelationshipSet")):
                    if relationshipSet is not None:
                        relationshipSetValid = True
                        if relationshipSet.link and relationshipSet.link not in relationshipSet.dts.qnameConcepts:
                            self.modelVersReport.error("verrelse:invalidLinkElementReference",
                                _("%(event)s %(relSet)s link %(link)s does not reference an element in its DTS"),
                                modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                link=relationshipSet.link)
                            relationshipSetValid = False
                        if relationshipSet.arc and relationshipSet.arc not in relationshipSet.dts.qnameConcepts:
                            self.modelVersReport.error("verrelse:invalidArcElementReference",
                                _("%(event)s %(relSet)s arc %(arc) does not reference an element in its DTS"),
                                modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                arc=relationshipSet.arc)
                            relationshipSetValid = False
                        if relationshipSet.linkrole and not (XbrlConst.isStandardRole(relationshipSet.linkrole) or
                                                             relationshipSet.linkrole in relationshipSet.dts.roleTypes):
                            self.modelVersReport.error("verrelse:invalidLinkrole",
                                _("%(event)s %(relSet)s linkrole %(linkrole)s does not reference an linkrole in its DTS"),
                                modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                linkrole=relationshipSet.linkrole)
                            relationshipSetValid = False
                        if relationshipSet.arcrole and not (XbrlConst.isStandardArcrole(relationshipSet.arcrole) or
                                                            relationshipSet.arcrole in relationshipSet.dts.arcroleTypes):
                            self.modelVersReport.error("verrelse:invalidArcrole",
                                _("%(event)s %(relSet)s arcrole %(arcrole)s does not reference an arcrole in its DTS"),
                                modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                arcrole=relationshipSet.arcrole)
                            relationshipSetValid = False
                        for relationship in relationshipSet.relationships:
                            # fromConcept checks
                            if relationship.fromConcept is None:
                                self.modelVersReport.error("verrelse:invalidConceptReference",
                                    _("%(event)s %(relSet)s relationship fromConcept %(conceptFrom)s does not reference a concept in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    conceptFrom=relationship.fromName)
                                relationshipSetValid = False
                            if relationship.toName and relationship.toConcept is None:
                                self.modelVersReport.error("verrelse:invalidConceptReference",
                                    _("%(event)s %(relSet)s relationship toConcept %(conceptTo)s does not reference a concept in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    conceptTo=relationship.toName)
                                relationshipSetValid = False
                            if relationshipSetValid: # test that relations exist
                                if relationship.fromRelationship is None:
                                    if relationship.toName:
                                        self.modelVersReport.error("verrelse:invalidRelationshipReference",
                                            _("%(event)s %(relSet)s no relationship found from fromConcept %(conceptFrom)s to toConcept %(conceptTo)s in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    conceptFrom=relationship.fromName, conceptTo=relationship.toName)
                                    else:
                                        self.modelVersReport.error("verrelse:invalidRelationshipReference",
                                            _("%(event)s %(relSet)s no relationship found fromConcept %(conceptFrom)s in its DTS"),
                                            modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                            conceptFrom=relationship.fromName)
                                    

                        
            
            '''
            # check instance aspect changes
            for iaChange in versReport.instanceAspectChanges:
                # validate related concepts
                for aspectName in ("{http://xbrl.org/2010/versioning-instance-aspects}concept", "{http://xbrl.org/2010/versioning-instance-aspects}member"):
                    for aspectElt in iaChange.iterdescendants(aspectName):
                        # check link attribute
                        link = aspectElement.get("link")
                        if link is not None:
                            iaChange.hrefToModelObject(link, dts)
            '''
            
        self.close()
Ejemplo n.º 18
0
 def linkbaseDiscover(self, linkbaseElement, inInstance=False):
     for lbElement in linkbaseElement.iterchildren():
         if isinstance(lbElement,ModelObject):
             lbLn = lbElement.localName
             lbNs = lbElement.namespaceURI
             if lbNs == XbrlConst.link:
                 if lbLn == "roleRef" or lbLn == "arcroleRef":
                     href = self.discoverHref(lbElement)
                     if href is None:
                         self.modelXbrl.error("xbrl:hrefMissing",
                                 _("Linkbase reference for %(linkbaseRefElement)s href attribute missing or malformed"),
                                 modelObject=lbElement, linkbaseRefElement=lbLn)
                     else:
                         self.hrefObjects.append(href)
                     continue
             if lbElement.get("{http://www.w3.org/1999/xlink}type") == "extended":
                 if isinstance(lbElement, ModelLink):
                     self.schemalocateElementNamespace(lbElement)
                     arcrolesFound = set()
                     dimensionArcFound = False
                     formulaArcFound = False
                     tableRenderingArcFound = False
                     linkQn = qname(lbElement)
                     linkrole = lbElement.get("{http://www.w3.org/1999/xlink}role")
                     isStandardExtLink = XbrlConst.isStandardResourceOrExtLinkElement(lbElement)
                     if inInstance:
                         #index footnote links even if no arc children
                         baseSetKeys = (("XBRL-footnotes",None,None,None), 
                                        ("XBRL-footnotes",linkrole,None,None))
                         for baseSetKey in baseSetKeys:
                             self.modelXbrl.baseSets[baseSetKey].append(lbElement)
                     for linkElement in lbElement.iterchildren():
                         if isinstance(linkElement,ModelObject):
                             self.schemalocateElementNamespace(linkElement)
                             xlinkType = linkElement.get("{http://www.w3.org/1999/xlink}type")
                             modelResource = None
                             if xlinkType == "locator":
                                 nonDTS = linkElement.namespaceURI != XbrlConst.link or linkElement.localName != "loc"
                                 # only link:loc elements are discovered or processed
                                 href = self.discoverHref(linkElement, nonDTS=nonDTS)
                                 if href is None:
                                     if isStandardExtLink:
                                         self.modelXbrl.error("xbrl:hrefMissing",
                                                 _("Locator href attribute missing or malformed in standard extended link"),
                                                 modelObejct=linkElement)
                                     else:
                                         self.modelXbrl.warning("arelle:hrefWarning",
                                                 _("Locator href attribute missing or malformed in non-standard extended link"),
                                                 modelObejct=linkElement)
                                 else:
                                     linkElement.modelHref = href
                                     modelResource = linkElement
                             elif xlinkType == "arc":
                                 arcQn = qname(linkElement)
                                 arcrole = linkElement.get("{http://www.w3.org/1999/xlink}arcrole")
                                 if arcrole not in arcrolesFound:
                                     if linkrole == "":
                                         linkrole = XbrlConst.defaultLinkRole
                                     #index by both arcrole and linkrole#arcrole and dimensionsions if applicable
                                     baseSetKeys = [(arcrole, linkrole, linkQn, arcQn)]
                                     baseSetKeys.append((arcrole, linkrole, None, None))
                                     baseSetKeys.append((arcrole, None, None, None))
                                     if XbrlConst.isDimensionArcrole(arcrole) and not dimensionArcFound:
                                         baseSetKeys.append(("XBRL-dimensions", None, None, None)) 
                                         baseSetKeys.append(("XBRL-dimensions", linkrole, None, None))
                                         dimensionArcFound = True
                                     if XbrlConst.isFormulaArcrole(arcrole) and not formulaArcFound:
                                         baseSetKeys.append(("XBRL-formulae", None, None, None)) 
                                         baseSetKeys.append(("XBRL-formulae", linkrole, None, None))
                                         formulaArcFound = True
                                     if XbrlConst.isTableRenderingArcrole(arcrole) and not tableRenderingArcFound:
                                         baseSetKeys.append(("Table-rendering", None, None, None)) 
                                         baseSetKeys.append(("Table-rendering", linkrole, None, None)) 
                                         tableRenderingArcFound = True
                                         self.modelXbrl.hasTableRendering = True
                                     for baseSetKey in baseSetKeys:
                                         self.modelXbrl.baseSets[baseSetKey].append(lbElement)
                                     arcrolesFound.add(arcrole)
                             elif xlinkType == "resource": 
                                 # create resource and make accessible by id for document
                                 modelResource = linkElement
                             if modelResource is not None:
                                 lbElement.labeledResources[linkElement.get("{http://www.w3.org/1999/xlink}label")] \
                                     .append(modelResource)
                 else:
                     self.modelXbrl.error("xbrl:schemaDefinitionMissing",
                             _("Linkbase extended link %(element)s missing schema definition"),
                             modelObject=lbElement, element=lbElement.prefixedName)
Ejemplo n.º 19
0
def checkFilingDTS(val, modelDocument, isEFM, isGFM, visited):
    global targetNamespaceDatePattern, efmFilenamePattern, htmlFileNamePattern, roleTypePattern, arcroleTypePattern, \
            arcroleDefinitionPattern, namePattern, linkroleDefinitionBalanceIncomeSheet
    if targetNamespaceDatePattern is None:
        targetNamespaceDatePattern = re.compile(
            r"/([12][0-9]{3})-([01][0-9])-([0-3][0-9])|"
            r"/([12][0-9]{3})([01][0-9])([0-3][0-9])|")
        efmFilenamePattern = re.compile(
            r"^[a-z0-9][a-zA-Z0-9_\.\-]*(\.xsd|\.xml|\.htm)$")
        htmlFileNamePattern = re.compile(
            r"^[a-zA-Z0-9][._a-zA-Z0-9-]*(\.htm)$")
        roleTypePattern = re.compile(r"^.*/role/[^/\s]+$")
        arcroleTypePattern = re.compile(r"^.*/arcrole/[^/\s]+$")
        arcroleDefinitionPattern = re.compile(
            r"^.*[^\\s]+.*$")  # at least one non-whitespace character
        namePattern = re.compile(
            "[][()*+?\\\\/^{}|@#%^=~`\"';:,<>&$\u00a3\u20ac]"
        )  # u20ac=Euro, u00a3=pound sterling
        linkroleDefinitionBalanceIncomeSheet = re.compile(
            r"[^-]+-\s+Statement\s+-\s+.*(income|balance|financial\W+position)",
            re.IGNORECASE)
    nonDomainItemNameProblemPattern = re.compile(
        r"({0})|(FirstQuarter|SecondQuarter|ThirdQuarter|FourthQuarter|[1-4]Qtr|Qtr[1-4]|ytd|YTD|HalfYear)(?:$|[A-Z\W])"
        .format(re.sub(r"\W", "", (val.entityRegistrantName or "").title())))

    visited.append(modelDocument)
    for referencedDocument, modelDocumentReference in modelDocument.referencesDocument.items(
    ):
        #6.07.01 no includes
        if modelDocumentReference.referenceType == "include":
            val.modelXbrl.error(
                ("EFM.6.07.01", "GFM.1.03.01"),
                _("Taxonomy schema %(schema)s includes %(include)s, only import is allowed"
                  ),
                modelObject=modelDocumentReference.referringModelObject,
                schema=modelDocument.basename,
                include=referencedDocument.basename)
        if referencedDocument not in visited and (
                referencedDocument.inDTS or referencedDocument.type
                == ModelDocument.Type.INLINEXBRLDOCUMENTSET
        ):  # ignore EdgarRenderer added non-DTS documents
            checkFilingDTS(val, referencedDocument, isEFM, isGFM, visited)

    if modelDocument.type == ModelDocument.Type.INLINEXBRLDOCUMENTSET:
        return  # nothing to check in inline document set surrogate parent

    if val.disclosureSystem.standardTaxonomiesDict is None:
        pass

    if isEFM:
        if modelDocument.uri in val.disclosureSystem.standardTaxonomiesDict:
            if modelDocument.targetNamespace:
                # check for duplicates of us-types, dei, and rr taxonomies
                match = standardNamespacesPattern.match(
                    modelDocument.targetNamespace)
                if match is not None:
                    conflictClass = match.group(2) or match.group(5)
                    if (conflictClass == 'us-gaap' and
                            match.group(3) < '2018') or conflictClass == 'srt':
                        val.standardNamespaceConflicts['srt+us-gaap'].add(
                            modelDocument
                        )  # ignore non-srt multi-usgaap in Filing.py
                    if conflictClass == 'us-gaap' or conflictClass == 'ifrs-full':
                        val.standardNamespaceConflicts['ifrs+us-gaap'].add(
                            modelDocument)
                    if conflictClass not in ('us-gaap', 'srt'):
                        val.standardNamespaceConflicts[conflictClass].add(
                            modelDocument)

        else:
            if len(modelDocument.basename) > 32:
                val.modelXbrl.error(
                    "EFM.5.01.01.tooManyCharacters",
                    _("Document file name %(filename)s must not exceed 32 characters."
                      ),
                    edgarCode="cp-0501-File-Name-Length",
                    modelObject=modelDocument,
                    filename=modelDocument.basename)
            if modelDocument.type != ModelDocument.Type.INLINEXBRLDOCUMENTSET:
                if modelDocument.type == ModelDocument.Type.INLINEXBRL:
                    _pattern = htmlFileNamePattern
                    _suffix = ".htm"
                else:
                    _pattern = efmFilenamePattern
                    _suffix = ".xsd or .xml"
                if not _pattern.match(modelDocument.basename):
                    val.modelXbrl.error(
                        "EFM.5.01.01",
                        _("Document file name %(filename)s must start with a-z or 0-9, contain upper or lower case letters, ., -, _, and end with %(suffix)s."
                          ),
                        edgarCode="cp-0501-File-Name",
                        modelObject=modelDocument,
                        filename=modelDocument.basename,
                        suffix=_suffix)

    if (modelDocument.type == ModelDocument.Type.SCHEMA
            and modelDocument.targetNamespace
            not in val.disclosureSystem.baseTaxonomyNamespaces
            and modelDocument.uri.startswith(val.modelXbrl.uriDir)):

        val.hasExtensionSchema = True
        # check schema contents types
        # 6.7.3 check namespace for standard authority
        targetNamespaceAuthority = UrlUtil.authority(
            modelDocument.targetNamespace)
        if targetNamespaceAuthority in val.disclosureSystem.standardAuthorities:
            val.modelXbrl.error(
                ("EFM.6.07.03", "GFM.1.03.03"),
                _("The target namespace, %(targetNamespace)s cannot have the same authority (%(targetNamespaceAuthority)s) as a standard "
                  "taxonomy, in %(schema)s.  Please change your target namespace."
                  ),
                edgarCode="fs-0703-Extension-Has-Standard-Namespace-Authority",
                modelObject=modelDocument,
                schema=modelDocument.basename,
                targetNamespace=modelDocument.targetNamespace,
                targetNamespaceAuthority=UrlUtil.authority(
                    modelDocument.targetNamespace, includeScheme=False))

        # 6.7.4 check namespace format
        if modelDocument.targetNamespace is None or not modelDocument.targetNamespace.startswith(
                "http://"):
            match = None
        else:
            targetNamespaceDate = modelDocument.targetNamespace[
                len(targetNamespaceAuthority):]
            match = targetNamespaceDatePattern.match(targetNamespaceDate)
        if match is not None:
            try:
                if match.lastindex == 3:
                    date = datetime.date(int(match.group(1)),
                                         int(match.group(2)),
                                         int(match.group(3)))
                elif match.lastindex == 6:
                    date = datetime.date(int(match.group(4)),
                                         int(match.group(5)),
                                         int(match.group(6)))
                else:
                    match = None
            except ValueError:
                match = None
        if match is None:
            val.modelXbrl.error(
                ("EFM.6.07.04", "GFM.1.03.04"),
                _("You did not adhere to the requirements for target namespace, for %(targetNamespace)s in %(schema)s.  "
                  "Please recheck your submission and adhere to the target namespace requirements."
                  ),
                edgarCode="cp-0704-Taxonomy-Valid-Target-Namespace",
                modelObject=modelDocument,
                schema=modelDocument.basename,
                targetNamespace=modelDocument.targetNamespace)
        elif val.fileNameDate and date > val.fileNameDate:
            val.modelXbrl.info(
                ("EFM.6.07.06", "GFM.1.03.06"),
                _("Warning: Taxonomy schema %(schema)s namespace %(targetNamespace)s has date later than document name date %(docNameDate)s"
                  ),
                modelObject=modelDocument,
                schema=modelDocument.basename,
                targetNamespace=modelDocument.targetNamespace,
                docNameDate=val.fileNameDate)

        if modelDocument.targetNamespace is not None:
            # 6.7.5 check prefix for _
            authority = UrlUtil.authority(modelDocument.targetNamespace)
            if not re.match(r"(http://|https://|ftp://|urn:)\w+", authority):
                val.modelXbrl.error(
                    ("EFM.6.07.05", "GFM.1.03.05"),
                    _("Taxonomy schema %(schema)s namespace %(targetNamespace)s must be a valid URI with a valid authority for the namespace."
                      ),
                    edgarCode="du-0705-Namespace-Authority",
                    modelObject=modelDocument,
                    schema=modelDocument.basename,
                    targetNamespace=modelDocument.targetNamespace)
            # may be multiple prefixes for namespace
            prefixes = [
                (prefix if prefix is not None else "")
                for prefix, NS in modelDocument.xmlRootElement.nsmap.items()
                if NS == modelDocument.targetNamespace
            ]
            if not prefixes:
                prefix = None
                val.modelXbrl.error(
                    ("EFM.6.07.07", "GFM.1.03.07"),
                    _("The schema does not supply a prefix for %(targetNamespace)s without an underscore character, in file %(schema)s. "
                      "Please provide or change a prefix"),
                    edgarCode="du-0707-Recommended-Prefix-Disallowed",
                    modelObject=modelDocument,
                    schema=modelDocument.basename,
                    targetNamespace=modelDocument.targetNamespace)
            else:
                prefix = prefixes[0]
                if len(prefixes) > 1:
                    val.modelXbrl.error(
                        ("EFM.6.07.07", "GFM.1.03.07"),
                        _("The schema does not supply a prefix for %(targetNamespace)s without an underscore character, in file %(schema)s. "
                          "Please provide or change a prefix"),
                        edgarCode="du-0707-Recommended-Prefix-Disallowed",
                        modelObject=modelDocument,
                        schema=modelDocument.basename,
                        targetNamespace=modelDocument.targetNamespace,
                        prefix=", ".join(prefixes))
                elif "_" in prefix:
                    val.modelXbrl.error(
                        ("EFM.6.07.07", "GFM.1.03.07"),
                        _("The schema does not supply a prefix for %(targetNamespace)s without an underscore character, in file %(schema)s. "
                          "Please provide or change a prefix"),
                        edgarCode="du-0707-Recommended-Prefix-Disallowed",
                        modelObject=modelDocument,
                        schema=modelDocument.basename,
                        targetNamespace=modelDocument.targetNamespace,
                        prefix=prefix)

            for modelConcept in modelDocument.xmlRootElement.iterdescendants(
                    tag="{http://www.w3.org/2001/XMLSchema}element"):
                if isinstance(modelConcept, ModelConcept):
                    # 6.7.16 name not duplicated in standard taxonomies
                    name = modelConcept.get("name")
                    if name is None:
                        name = ""
                        if modelConcept.get("ref") is not None:
                            continue  # don't validate ref's here
                    for c in val.modelXbrl.nameConcepts.get(name, []):
                        if c.modelDocument != modelDocument:
                            if not c.modelDocument.uri.startswith(
                                    val.modelXbrl.uriDir):
                                val.modelXbrl.error(
                                    ("EFM.6.07.16", "GFM.1.03.18"),
                                    _("Your extension taxonomy contains an element, %(concept)s, which has the same name as an element in the base taxonomy, "
                                      "%(standardConcept)s.  Please ensure that this extension is appropriate and if so, please change the extension concept name."
                                      ),
                                    edgarCode=
                                    "cp-0716-Element-Name-Same-As-Base",
                                    modelObject=(modelConcept, c),
                                    concept=modelConcept.qname,
                                    standardSchema=c.modelDocument.basename,
                                    standardConcept=c.qname)

                    # 6.7.17 id properly formed
                    _id = modelConcept.id
                    requiredId = (prefix
                                  if prefix is not None else "") + "_" + name
                    if _id != requiredId:
                        val.modelXbrl.error(
                            ("EFM.6.07.17", "GFM.1.03.19"),
                            _("You did not adhere to the declarations for concepts by containing an 'id' attribute whose value begins with the recommended "
                              "namespace prefix of the taxonomy, followed by an underscore, followed by an element name, for the concept %(concept)s.  "
                              "Please recheck your submission."),
                            edgarCode="cp-0717-Element-Id",
                            modelObject=modelConcept,
                            concept=modelConcept.qname,
                            id=_id,
                            requiredId=requiredId)

                    # 6.7.18 nillable is true
                    nillable = modelConcept.get("nillable")
                    if nillable != "true" and modelConcept.isItem:
                        val.modelXbrl.error(
                            ("EFM.6.07.18", "GFM.1.03.20"),
                            _("Element %(concept)s is declared without a 'true' value for the nillable attribute.  Please set the value to 'true'."
                              ),
                            edgarCode="du-0718-Nillable-Not-True",
                            modelObject=modelConcept,
                            schema=modelDocument.basename,
                            concept=name,
                            nillable=nillable)

                    # 6.7.19 not tuple
                    if modelConcept.isTuple:
                        val.modelXbrl.error(
                            ("EFM.6.07.19", "GFM.1.03.21"),
                            _("You provided an extension concept which is a tuple, %(concept)s.  Please remove tuples and check your submission."
                              ),
                            edgarCode="cp-0719-No-Tuple-Element",
                            modelObject=modelConcept,
                            concept=modelConcept.qname)

                    # 6.7.20 no typed domain ref
                    if modelConcept.isTypedDimension:
                        val.modelXbrl.error(
                            ("EFM.6.07.20", "GFM.1.03.22"),
                            _("There is an xbrldt:typedDomainRef attribute on %(concept)s (%(typedDomainRef)s). Please remove it."
                              ),
                            edgarCode="du-0720-Typed-Domain-Ref-Disallowed",
                            modelObject=modelConcept,
                            concept=modelConcept.qname,
                            typedDomainRef=modelConcept.typedDomainElement.
                            qname if modelConcept.typedDomainElement
                            is not None else modelConcept.typedDomainRef)

                    # 6.7.21 abstract must be duration
                    isDuration = modelConcept.periodType == "duration"
                    if modelConcept.isAbstract and not isDuration:
                        val.modelXbrl.error(
                            ("EFM.6.07.21", "GFM.1.03.23"),
                            _("Element %(concept)s is declared as an abstract item with period type 'instant'.  Please change it to 'duration' or "
                              "make the element not abstract."),
                            edgarCode="du-0721-Abstract-Is-Instant",
                            modelObject=modelConcept,
                            schema=modelDocument.basename,
                            concept=modelConcept.qname)

                    # 6.7.22 abstract must be stringItemType
                    ''' removed SEC EFM v.17, Edgar release 10.4, and GFM 2011-04-08
                    if modelConcept.abstract == "true" and modelConcept.typeQname != XbrlConst. qnXbrliStringItemType:
                        val.modelXbrl.error(("EFM.6.07.22", "GFM.1.03.24"),
                            _("Concept %(concept)s  is abstract but type is not xbrli:stringItemType"),
                            modelObject=modelConcept, concept=modelConcept.qname)
					'''
                    substitutionGroupQname = modelConcept.substitutionGroupQname
                    # 6.7.23 Axis must be subs group dimension
                    if name.endswith("Axis") ^ (
                            substitutionGroupQname
                            == XbrlConst.qnXbrldtDimensionItem):
                        val.modelXbrl.error(
                            ("EFM.6.07.23", "GFM.1.03.25"),
                            _("The substitution group 'xbrldt:dimensionItem' is only consistent with an element name that ends with 'Axis'.  "
                              "Please change %(conceptLocalName)s or change the substitutionGroup."
                              ),
                            edgarCode="du-0723-Axis-Dimension-Name-Mismatch",
                            modelObject=modelConcept,
                            concept=modelConcept.qname,
                            conceptLocalName=modelConcept.qname.localName)

                    # 6.7.24 Table must be subs group hypercube
                    if name.endswith("Table") ^ (
                            substitutionGroupQname
                            == XbrlConst.qnXbrldtHypercubeItem):
                        val.modelXbrl.error(
                            ("EFM.6.07.24", "GFM.1.03.26"),
                            _("The substitution group 'xbrldt:hypercubeItem' is only allowed with an element name that ends with 'Table'.  "
                              "Please change %(conceptLocalName)s or change the substitutionGroup."
                              ),
                            edgarCode="du-0724-Table-Hypercube-Name-Mismatch",
                            modelObject=modelConcept,
                            schema=modelDocument.basename,
                            concept=modelConcept.qname,
                            conceptLocalName=modelConcept.qname.localName)

                    # 6.7.25 if neither hypercube or dimension, substitution group must be item
                    if substitutionGroupQname not in (
                            None, XbrlConst.qnXbrldtDimensionItem,
                            XbrlConst.qnXbrldtHypercubeItem,
                            XbrlConst.qnXbrliItem):
                        val.modelXbrl.error(
                            ("EFM.6.07.25", "GFM.1.03.27"),
                            _("The substitution group attribute value %(substitutionGroup)s of element %(conceptLocalName)s is not allowed.  "
                              "Please change it to one of 'xbrli:item', 'xbrldt:dimensionItem' or 'xbrldt:hypercubeItem'."
                              ),
                            edgarCode="du-0725-Substitution-Group-Custom",
                            modelObject=modelConcept,
                            concept=modelConcept.qname,
                            conceptLocalName=modelConcept.qname.localName,
                            substitutionGroup=modelConcept.
                            substitutionGroupQname)

                    # 6.7.26 Table must be subs group hypercube
                    if name.endswith(
                            "LineItems") and modelConcept.abstract != "true":
                        val.modelXbrl.error(
                            ("EFM.6.07.26", "GFM.1.03.28"),
                            _("The element %(conceptLocalName)s ends with 'LineItems' but is not abstract. Please change %(conceptLocalName)s or "
                              "the value of the 'abstract' attribute."),
                            edgarCode=
                            "du-0726-LineItems-Abstract-Name-Mismatch",
                            modelObject=modelConcept,
                            concept=modelConcept.qname,
                            conceptLocalName=modelConcept.qname.localName)

                    # 6.7.27 type domainMember must end with Domain or Member
                    conceptType = modelConcept.type
                    isDomainItemType = conceptType is not None and conceptType.isDomainItemType
                    endsWithDomainOrMember = name.endswith(
                        "Domain") or name.endswith("Member")
                    if isDomainItemType != endsWithDomainOrMember:
                        val.modelXbrl.error(
                            ("EFM.6.07.27", "GFM.1.03.29"),
                            _("The type 'us-types:domainItemType' is only allowed with an element name that ends with 'Domain' or 'Member'.  "
                              "Please change %(conceptLocalName)s or change the type."
                              ),
                            edgarCode="du-0727-Domain-Type-Name-Mismatch",
                            modelObject=modelConcept,
                            concept=modelConcept.qname,
                            conceptLocalName=modelConcept.qname.localName)

                    # 6.7.28 domainItemType must be duration
                    if isDomainItemType and not isDuration:
                        val.modelXbrl.error(
                            ("EFM.6.07.28", "GFM.1.03.30"),
                            _("Element %(conceptLocalName)s is declared as a us-types:domainItemType with period type 'instant'.  "
                              "Please change it to 'duration' or change the item type."
                              ),
                            edgarCode="du-0728-Domain-Member-Is-Instant",
                            modelObject=modelConcept,
                            concept=modelConcept.qname,
                            conceptLocalName=modelConcept.qname.localName)

                    #6.7.31 (version 27) fractions
                    if modelConcept.isFraction:
                        val.modelXbrl.error(
                            "EFM.6.07.31",
                            _("Element %(concept)s is declared as a fraction item type.  Change or remove the declaration."
                              ),
                            edgarCode="du-0731-Fraction-Item-Type",
                            modelObject=modelConcept,
                            concept=modelConcept.qname)

                    #6.7.32 (version 27) instant non numeric
                    if modelConcept.isItem and (not modelConcept.isNumeric
                                                and not isDuration
                                                and not modelConcept.isAbstract
                                                and not isDomainItemType):
                        val.modelXbrl.error(
                            "EFM.6.07.32",
                            _("Declaration of element %(concept)s in %(schema)s must have xbrli:periodType of 'duration' because its base type is not numeric."
                              ),
                            edgarCode="rq-0732-Nonnnumeric-Must-Be-Duration",
                            modelObject=modelConcept,
                            schema=modelDocument.basename,
                            concept=modelConcept.qname)

                    # 6.8.5 semantic check, check LC3 name
                    if name:
                        if not name[0].isupper():
                            val.modelXbrl.log(
                                "ERROR-SEMANTIC", ("EFM.6.08.05.firstLetter",
                                                   "GFM.2.03.05.firstLetter"),
                                _("Concept %(concept)s name must start with a capital letter"
                                  ),
                                modelObject=modelConcept,
                                concept=modelConcept.qname)
                        if namePattern.search(name):
                            val.modelXbrl.log(
                                "ERROR-SEMANTIC",
                                ("EFM.6.08.05.disallowedCharacter",
                                 "GFM.2.03.05.disallowedCharacter"),
                                _("Concept %(concept)s has disallowed name character"
                                  ),
                                modelObject=modelConcept,
                                concept=modelConcept.qname)
                        if len(name) > 200:
                            val.modelXbrl.log(
                                "ERROR-SEMANTIC",
                                "EFM.6.08.05.nameLength",
                                _("Concept %(concept)s name length %(namelength)s exceeds 200 characters"
                                  ),
                                modelObject=modelConcept,
                                concept=modelConcept.qname,
                                namelength=len(name))

                    if isEFM:
                        label = modelConcept.label(lang="en-US",
                                                   fallbackToQname=False)
                        if label:
                            # allow Joe's Bar, N.A.  to be JoesBarNA -- remove ', allow A. as not article "a"
                            lc3name = ''.join(
                                re.sub(r"['.-]", "", (
                                    w[0] or w[2] or w[3] or w[4])).title()
                                for w in re.findall(
                                    r"((\w+')+\w+)|(A[.-])|([.-]A(?=\W|$))|(\w+)",
                                    label
                                )  # EFM implies this should allow - and . re.findall(r"[\w\-\.]+", label)
                                if w[4].lower() not in ("the", "a", "an"))
                            if not (name == lc3name or
                                    (name and lc3name and lc3name[0].isdigit()
                                     and name[1:] == lc3name and
                                     (name[0].isalpha() or name[0] == '_'))):
                                val.modelXbrl.log(
                                    "WARNING-SEMANTIC",
                                    "EFM.6.08.05.LC3",
                                    _("Concept %(concept)s should match expected LC3 composition %(lc3name)s"
                                      ),
                                    modelObject=modelConcept,
                                    concept=modelConcept.qname,
                                    lc3name=lc3name)

                    if conceptType is not None:
                        # 6.8.6 semantic check
                        if not isDomainItemType and conceptType.qname != XbrlConst.qnXbrliDurationItemType:
                            nameProblems = nonDomainItemNameProblemPattern.findall(
                                name)
                            if any(
                                    any(t) for t in nameProblems
                            ):  # list of tuples with possibly nonempty strings
                                val.modelXbrl.log(
                                    "WARNING-SEMANTIC",
                                    ("EFM.6.08.06", "GFM.2.03.06"),
                                    _("Concept %(concept)s should not contain company or period information, found: %(matches)s"
                                      ),
                                    modelObject=modelConcept,
                                    concept=modelConcept.qname,
                                    matches=", ".join(''.join(t)
                                                      for t in nameProblems))

                        if conceptType.qname == XbrlConst.qnXbrliMonetaryItemType:
                            if not modelConcept.balance:
                                # 6.8.11 may not appear on a income or balance statement
                                if any(
                                        linkroleDefinitionBalanceIncomeSheet.
                                        match(roleType.definition)
                                        for rel in val.modelXbrl.
                                        relationshipSet(XbrlConst.parentChild).
                                        toModelObject(modelConcept)
                                        for roleType in val.modelXbrl.
                                        roleTypes.get(rel.linkrole, ())):
                                    val.modelXbrl.log(
                                        "ERROR-SEMANTIC",
                                        ("EFM.6.08.11", "GFM.2.03.11"),
                                        _("Concept %(concept)s must have a balance because it appears in a statement of income or balance sheet"
                                          ),
                                        modelObject=modelConcept,
                                        concept=modelConcept.qname)
                                # 6.11.5 semantic check, must have a documentation label
                                stdLabel = modelConcept.label(
                                    lang="en-US", fallbackToQname=False)
                                defLabel = modelConcept.label(
                                    preferredLabel=XbrlConst.
                                    documentationLabel,
                                    lang="en-US",
                                    fallbackToQname=False)
                                if not defLabel or (  # want different words than std label
                                        stdLabel
                                        and re.findall(r"\w+", stdLabel)
                                        == re.findall(r"\w+", defLabel)):
                                    val.modelXbrl.log(
                                        "ERROR-SEMANTIC",
                                        ("EFM.6.11.05", "GFM.2.04.04"),
                                        _("Concept %(concept)s is monetary without a balance and must have a documentation label that disambiguates its sign"
                                          ),
                                        modelObject=modelConcept,
                                        concept=modelConcept.qname)

                        # 6.8.16 semantic check
                        if conceptType.qname == XbrlConst.qnXbrliDateItemType and modelConcept.periodType != "duration":
                            val.modelXbrl.log(
                                "ERROR-SEMANTIC",
                                ("EFM.6.08.16", "GFM.2.03.16"),
                                _("Concept %(concept)s of type xbrli:dateItemType must have periodType duration"
                                  ),
                                modelObject=modelConcept,
                                concept=modelConcept.qname)

                        # 6.8.17 semantic check
                        if conceptType.qname == XbrlConst.qnXbrliStringItemType and modelConcept.periodType != "duration":
                            val.modelXbrl.log(
                                "ERROR-SEMANTIC",
                                ("EFM.6.08.17", "GFM.2.03.17"),
                                _("Concept %(concept)s of type xbrli:stringItemType must have periodType duration"
                                  ),
                                modelObject=modelConcept,
                                concept=modelConcept.qname)

        # 6.7.8 check for embedded linkbase
        for e in modelDocument.xmlRootElement.iterdescendants(
                tag="{http://www.xbrl.org/2003/linkbase}linkbase"):
            if isinstance(e, ModelObject):
                val.modelXbrl.error(
                    ("EFM.6.07.08", "GFM.1.03.08"),
                    _("Your filing contained embedded linkbases in %(schema)s.  Please recheck your submission and remove all embedded linkbases."
                      ),
                    edgarCode="cp-0708-No-Embedded-Linkbases",
                    modelObject=e,
                    schema=modelDocument.basename)
                break

        requiredUsedOns = {
            XbrlConst.qnLinkPresentationLink, XbrlConst.qnLinkCalculationLink,
            XbrlConst.qnLinkDefinitionLink
        }

        standardUsedOns = {
            XbrlConst.qnLinkLabel,
            XbrlConst.qnLinkReference,
            XbrlConst.qnLinkDefinitionArc,
            XbrlConst.qnLinkCalculationArc,
            XbrlConst.qnLinkPresentationArc,
            XbrlConst.qnLinkLabelArc,
            XbrlConst.qnLinkReferenceArc,
            # per WH, private footnote arc and footnore resource roles are not allowed
            XbrlConst.qnLinkFootnoteArc,
            XbrlConst.qnLinkFootnote,
        }

        # 6.7.9 role types authority
        for e in modelDocument.xmlRootElement.iterdescendants(
                tag="{http://www.xbrl.org/2003/linkbase}roleType"):
            if isinstance(e, ModelObject):
                roleURI = e.get("roleURI")
                if targetNamespaceAuthority != UrlUtil.authority(roleURI):
                    val.modelXbrl.error(
                        ("EFM.6.07.09", "GFM.1.03.09"),
                        _("Role %(roleType)s does not begin with %(targetNamespace)s's scheme and authority. "
                          "Please change the role URI or target namespace URI."
                          ),
                        edgarCode="du-0709-Role-Namespace-Mismatch",
                        modelObject=e,
                        roleType=roleURI,
                        targetNamespaceAuthority=targetNamespaceAuthority,
                        targetNamespace=modelDocument.targetNamespace)
                # 6.7.9 end with .../role/lc3 name
                if not roleTypePattern.match(roleURI):
                    val.modelXbrl.warning(
                        ("EFM.6.07.09.roleEnding", "GFM.1.03.09"),
                        "RoleType %(roleType)s should end with /role/{LC3name}",
                        modelObject=e,
                        roleType=roleURI)

                # 6.7.10 only one role type declaration in DTS
                modelRoleTypes = val.modelXbrl.roleTypes.get(roleURI)
                if modelRoleTypes is not None:
                    modelRoleType = modelRoleTypes[0]
                    definition = modelRoleType.definitionNotStripped
                    usedOns = modelRoleType.usedOns
                    if len(modelRoleTypes) == 1:
                        # 6.7.11 used on's for pre, cal, def if any has a used on
                        if not usedOns.isdisjoint(requiredUsedOns) and len(
                                requiredUsedOns - usedOns) > 0:
                            val.modelXbrl.error(
                                ("EFM.6.07.11", "GFM.1.03.11"),
                                _("The role %(roleType)s did not provide a usedOn element for all three link types (presentation, "
                                  "calculation and definition), missing %(usedOn)s. Change the declaration to be for all three types of link, and resubmit."
                                  ),
                                edgarCode=
                                "du-0711-Role-Type-Declaration-Incomplete",
                                modelObject=e,
                                roleType=roleURI,
                                usedOn=requiredUsedOns - usedOns)

                        # 6.7.12 definition match pattern
                        if (val.disclosureSystem.roleDefinitionPattern
                                is not None and
                            (definition is None or not val.disclosureSystem.
                             roleDefinitionPattern.match(definition))):
                            val.modelXbrl.error(
                                ("EFM.6.07.12", "GFM.1.03.12-14"),
                                _("The definition '%(definition)s' of role %(roleType)s does not match the expected format. "
                                  "Please check that the definition matches {number} - {type} - {text}."
                                  ),
                                edgarCode="rq-0712-Role-Definition-Mismatch",
                                modelObject=e,
                                roleType=roleURI,
                                definition=(definition or ""))

                    if usedOns & standardUsedOns:  # semantics check
                        val.modelXbrl.log(
                            "ERROR-SEMANTIC", ("EFM.6.08.03", "GFM.2.03.03"),
                            _("RoleType %(roleuri)s is defined using role types already defined by standard roles for: %(qnames)s"
                              ),
                            modelObject=e,
                            roleuri=roleURI,
                            qnames=', '.join(
                                str(qn) for qn in usedOns & standardUsedOns))

        # 6.7.13 arcrole types authority
        for e in modelDocument.xmlRootElement.iterdescendants(
                tag="{http://www.xbrl.org/2003/linkbase}arcroleType"):
            if isinstance(e, ModelObject):
                arcroleURI = e.get("arcroleURI")
                if targetNamespaceAuthority != UrlUtil.authority(arcroleURI):
                    val.modelXbrl.error(
                        ("EFM.6.07.13", "GFM.1.03.15"),
                        _("Relationship role %(arcroleType)s does not begin with %(targetNamespace)s's scheme and authority.  "
                          "Please change the relationship role URI or target namespace URI."
                          ),
                        edgarCode="du-0713-Arcrole-Namespace-Mismatch",
                        modelObject=e,
                        arcroleType=arcroleURI,
                        targetNamespaceAuthority=targetNamespaceAuthority,
                        targetNamespace=modelDocument.targetNamespace)
                # 6.7.13 end with .../arcrole/lc3 name
                if not arcroleTypePattern.match(arcroleURI):
                    val.modelXbrl.warning(
                        ("EFM.6.07.13.arcroleEnding", "GFM.1.03.15"),
                        _("ArcroleType %(arcroleType)s should end with /arcrole/{LC3name}"
                          ),
                        modelObject=e,
                        arcroleType=arcroleURI)

                # 6.7.15 definition match pattern
                modelRoleTypes = val.modelXbrl.arcroleTypes[arcroleURI]
                definition = modelRoleTypes[0].definition
                if definition is None or not arcroleDefinitionPattern.match(
                        definition):
                    val.modelXbrl.error(
                        ("EFM.6.07.15", "GFM.1.03.17"),
                        _("Relationship role declaration %(arcroleType)s is missing a definition.  Please provide a definition."
                          ),
                        edgarCode="du-0715-Arcrole-Definition-Missing",
                        modelObject=e,
                        arcroleType=arcroleURI)

                # semantic checks
                usedOns = modelRoleTypes[0].usedOns
                if usedOns & standardUsedOns:  # semantics check
                    val.modelXbrl.log(
                        "ERROR-SEMANTIC", ("EFM.6.08.03", "GFM.2.03.03"),
                        _("ArcroleType %(arcroleuri)s is defined using role types already defined by standard arcroles for: %(qnames)s"
                          ),
                        modelObject=e,
                        arcroleuri=arcroleURI,
                        qnames=', '.join(
                            str(qn) for qn in usedOns & standardUsedOns))

        #6.3.3 filename check
        m = re.match(r"^\w+-([12][0-9]{3}[01][0-9][0-3][0-9]).xsd$",
                     modelDocument.basename)
        if m:
            try:  # check date value
                datetime.datetime.strptime(m.group(1), "%Y%m%d").date()
                # date and format are ok, check "should" part of 6.3.3
                if val.fileNameBasePart:
                    expectedFilename = "{0}-{1}.xsd".format(
                        val.fileNameBasePart, val.fileNameDatePart)
                    if modelDocument.basename != expectedFilename:
                        val.modelXbrl.log(
                            "WARNING-SEMANTIC", ("EFM.6.03.03.matchInstance",
                                                 "GFM.1.01.01.matchInstance"),
                            _('Schema file name warning: %(filename)s, should match %(expectedFilename)s'
                              ),
                            modelObject=modelDocument,
                            filename=modelDocument.basename,
                            expectedFilename=expectedFilename)
            except ValueError:
                val.modelXbrl.error(
                    (val.EFM60303, "GFM.1.01.01"),
                    _('Invalid schema file base name part (date) in "{base}-{yyyymmdd}.xsd": %(filename)s'
                      ),
                    modelObject=modelDocument,
                    filename=modelDocument.basename,
                    messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))
        else:
            val.modelXbrl.error(
                (val.EFM60303, "GFM.1.01.01"),
                _('Invalid schema file name, must match "{base}-{yyyymmdd}.xsd": %(filename)s'
                  ),
                modelObject=modelDocument,
                filename=modelDocument.basename,
                messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))

    elif modelDocument.type == ModelDocument.Type.LINKBASE:
        # if it is part of the submission (in same directory) check name
        labelRels = None
        if modelDocument.filepath.startswith(
                val.modelXbrl.modelDocument.filepathdir):
            #6.3.3 filename check
            extLinkElt = XmlUtil.descendant(
                modelDocument.xmlRootElement, XbrlConst.link, "*",
                "{http://www.w3.org/1999/xlink}type", "extended")
            if extLinkElt is None:  # no ext link element
                val.modelXbrl.error(
                    (val.EFM60303 + ".noLinkElement",
                     "GFM.1.01.01.noLinkElement"),
                    _('Invalid linkbase file name: %(filename)s, has no extended link element, cannot determine link type.'
                      ),
                    modelObject=modelDocument,
                    filename=modelDocument.basename,
                    messageCodes=("EFM.6.03.03.noLinkElement",
                                  "EFM.6.23.01.noLinkElement",
                                  "GFM.1.01.01.noLinkElement"))
            elif extLinkElt.localName not in extLinkEltFileNameEnding:
                val.modelXbrl.error(
                    "EFM.6.03.02",
                    _('Invalid linkbase link element %(linkElement)s in %(filename)s'
                      ),
                    modelObject=modelDocument,
                    linkElement=extLinkElt.localName,
                    filename=modelDocument.basename)
            else:
                m = re.match(
                    r"^\w+-([12][0-9]{3}[01][0-9][0-3][0-9])(_[a-z]{3}).xml$",
                    modelDocument.basename)
                expectedSuffix = extLinkEltFileNameEnding[extLinkElt.localName]
                if m and m.group(2) == expectedSuffix:
                    try:  # check date value
                        datetime.datetime.strptime(m.group(1), "%Y%m%d").date()
                        # date and format are ok, check "should" part of 6.3.3
                        if val.fileNameBasePart:
                            expectedFilename = "{0}-{1}{2}.xml".format(
                                val.fileNameBasePart, val.fileNameDatePart,
                                expectedSuffix)
                            if modelDocument.basename != expectedFilename:
                                val.modelXbrl.log(
                                    "WARNING-SEMANTIC",
                                    ("EFM.6.03.03.matchInstance",
                                     "GFM.1.01.01.matchInstance"),
                                    _('Linkbase name warning: %(filename)s should match %(expectedFilename)s'
                                      ),
                                    modelObject=modelDocument,
                                    filename=modelDocument.basename,
                                    expectedFilename=expectedFilename)
                    except ValueError:
                        val.modelXbrl.error(
                            (val.EFM60303, "GFM.1.01.01"),
                            _('Invalid linkbase base file name part (date) in "{base}-{yyyymmdd}_{suffix}.xml": %(filename)s'
                              ),
                            modelObject=modelDocument,
                            filename=modelDocument.basename,
                            messageCodes=("EFM.6.03.03", "EFM.6.23.01",
                                          "GFM.1.01.01"))
                else:
                    val.modelXbrl.error(
                        (val.EFM60303, "GFM.1.01.01"),
                        _('Invalid linkbase name, must match "{base}-{yyyymmdd}%(expectedSuffix)s.xml": %(filename)s'
                          ),
                        modelObject=modelDocument,
                        filename=modelDocument.basename,
                        expectedSuffix=expectedSuffix,
                        messageCodes=("EFM.6.03.03", "EFM.6.23.01",
                                      "GFM.1.01.01"))
                if extLinkElt.localName == "labelLink":
                    if labelRels is None:
                        labelRels = val.modelXbrl.relationshipSet(
                            XbrlConst.conceptLabel)
                    for labelElt in XmlUtil.children(extLinkElt,
                                                     XbrlConst.link, "label"):
                        # 6.10.9
                        if XbrlConst.isNumericRole(labelElt.role):
                            for rel in labelRels.toModelObject(labelElt):
                                if rel.fromModelObject is not None and not rel.fromModelObject.isNumeric:
                                    val.modelXbrl.error(
                                        "EFM.6.10.09",
                                        _("Non-numeric element %(concept)s has a label role for numeric elements: %(role)s. "
                                          "Please change the role attribute."),
                                        edgarCode="du-1009-Numeric-Label-Role",
                                        modelObject=(labelElt,
                                                     rel.fromModelObject),
                                        concept=rel.fromModelObject.qname,
                                        role=labelElt.role)
Ejemplo n.º 20
0
def init(modelXbrl):
    # setup modelXbrl for rendering evaluation

    # dimension defaults required in advance of validation
    from arelle import ValidateXbrlDimensions, ValidateFormula, ModelDocument
    ValidateXbrlDimensions.loadDimensionDefaults(modelXbrl)
    
    hasXbrlTables = False
    
    # validate table linkbase dimensions
    for baseSetKey in modelXbrl.baseSets.keys():
        arcrole, ELR, linkqname, arcqname = baseSetKey
        if ELR and linkqname and arcqname and XbrlConst.isTableRenderingArcrole(arcrole):
            ValidateFormula.checkBaseSet(modelXbrl, arcrole, ELR, modelXbrl.relationshipSet(arcrole,ELR,linkqname,arcqname))
            if arcrole in (XbrlConst.tableBreakdown, XbrlConst.tableAxis2011):
                hasXbrlTables = True

    # provide context for view
    if modelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE:
        instance = None # use instance of the entry pont
    else: # need dummy instance
        instance = ModelDocument.create(modelXbrl, ModelDocument.Type.INSTANCE, 
                                        "dummy.xml",  # fake URI and fake schemaRef 
                                        ("http://www.xbrl.org/2003/xbrl-instance-2003-12-31.xsd",))
        
    if hasXbrlTables:
        # formula processor is needed for 2011 XBRL tables but not for 2010 Eurofiling tables
        modelXbrl.rendrCntx = XPathContext.create(modelXbrl, instance)
        
        modelXbrl.profileStat(None)
        
        # setup fresh parameters from formula optoins
        modelXbrl.parameters = modelXbrl.modelManager.formulaOptions.typedParameters()
        
        # validate parameters and custom function signatures
        ValidateFormula.validate(modelXbrl, xpathContext=modelXbrl.rendrCntx, parametersOnly=True, statusMsg=_("compiling rendering tables"))
        
        # check and extract message expressions into compilable programs
        for msgArcrole in (XbrlConst.tableDefinitionNodeMessage, XbrlConst.tableDefinitionNodeSelectionMessage,
                           XbrlConst.tableAxisMessage2011, XbrlConst.tableAxisSelectionMessage2011):
            for msgRel in modelXbrl.relationshipSet(msgArcrole).modelRelationships:
                ValidateFormula.checkMessageExpressions(modelXbrl, msgRel.toModelObject)
                
        # compile and validate tables
        for modelTable in modelXbrl.modelRenderingTables:
            modelTable.fromInstanceQnames = None # required if referred to by variables scope chaining
            modelTable.compile()

            # check aspectModel
            if modelTable.aspectModel not in ("non-dimensional", "dimensional"):
                modelXbrl.error("xbrlte:unknownAspectModel",
                    _("Table %(xlinkLabel)s, aspect model %(aspectModel)s not recognized"),
                    modelObject=modelTable, xlinkLabel=modelTable.xlinkLabel, aspectModel=modelTable.aspectModel)
            else:
                modelTable.priorAspectAxisDisposition = {}
                # check ordinate aspects against aspectModel
                oppositeAspectModel = (_DICT_SET({'dimensional','non-dimensional'}) - _DICT_SET({modelTable.aspectModel})).pop()
                uncoverableAspects = aspectModels[oppositeAspectModel] - aspectModels[modelTable.aspectModel]
                for tblAxisRel in modelXbrl.relationshipSet((XbrlConst.tableBreakdown,XbrlConst.tableAxis2011)).fromModelObject(modelTable):
                    checkDefinitionNodeAspectModel(modelXbrl, modelTable, tblAxisRel, uncoverableAspects)
                del modelTable.priorAspectAxisDisposition
    
        modelXbrl.profileStat(_("compileTables"))
Ejemplo n.º 21
0
 def linkbaseDiscover(self, linkbaseElement, inInstance=False):
     for lbElement in linkbaseElement.childNodes:
         if lbElement.nodeType == 1: #element
             lbLn = lbElement.localName
             lbNs = lbElement.namespaceURI
             if lbNs == XbrlConst.link:
                 if lbLn == "roleRef" or lbLn == "arcroleRef":
                     href = self.discoverHref(lbElement)
                     if href is None:
                         self.modelXbrl.error(
                                 "Linkbase in {0} {1} href attribute missing or malformed".format(
                                   os.path.basename(self.uri),
                                   lbLn),
                                 "err", "xbrl:hrefMissing")
                     else:
                         self.hrefObjects.append(href)
                     continue
             if lbElement.getAttributeNS(XbrlConst.xlink, "type") == "extended":
                 self.schemalocateElementNamespace(lbElement)
                 arcrolesFound = set()
                 dimensionArcFound = False
                 formulaArcFound = False
                 euRenderingArcFound = False
                 linkQn = qname(lbElement)
                 linkrole = lbElement.getAttributeNS(XbrlConst.xlink, "role")
                 modelLink = ModelObject.createLink(self, lbElement)
                 if inInstance:
                     #index footnote links even if no arc children
                     baseSetKeys = (("XBRL-footnotes",None,None,None), 
                                    ("XBRL-footnotes",linkrole,None,None))
                     for baseSetKey in baseSetKeys:
                         self.modelXbrl.baseSets[baseSetKey].append(modelLink)
                 for linkElement in lbElement.childNodes:
                     if linkElement.nodeType == 1: #element
                         self.schemalocateElementNamespace(linkElement)
                         xlinkType = linkElement.getAttributeNS(XbrlConst.xlink, "type")
                         modelResource = None
                         if xlinkType == "locator":
                             nonDTS = linkElement.namespaceURI != XbrlConst.link or linkElement.localName != "loc"
                             # only link:loc elements are discovered or processed
                             href = self.discoverHref(linkElement, nonDTS=nonDTS)
                             if href is None:
                                 self.modelXbrl.error(
                                         "Linkbase in {0} {1} href attribute missing or malformed".format(
                                           os.path.basename(self.uri),
                                           lbLn),
                                         "err", "xbrl:hrefMissing")
                             else:
                                 modelResource = ModelObject.createLocator(self, linkElement, href)
                         elif xlinkType == "arc":
                             arcQn = qname(linkElement)
                             arcrole = linkElement.getAttributeNS(XbrlConst.xlink, "arcrole")
                             if arcrole not in arcrolesFound:
                                 if linkrole == "":
                                     linkrole = XbrlConst.defaultLinkRole
                                 #index by both arcrole and linkrole#arcrole and dimensionsions if applicable
                                 baseSetKeys = [(arcrole, linkrole, linkQn, arcQn)]
                                 baseSetKeys.append((arcrole, linkrole, None, None))
                                 baseSetKeys.append((arcrole, None, None, None))
                                 if XbrlConst.isDimensionArcrole(arcrole) and not dimensionArcFound:
                                     baseSetKeys.append(("XBRL-dimensions", None, None, None)) 
                                     baseSetKeys.append(("XBRL-dimensions", linkrole, None, None))
                                     dimensionArcFound = True
                                 if XbrlConst.isFormulaArcrole(arcrole) and not formulaArcFound:
                                     baseSetKeys.append(("XBRL-formulae", None, None, None)) 
                                     baseSetKeys.append(("XBRL-formulae", linkrole, None, None))
                                     formulaArcFound = True
                                 if XbrlConst.isEuRenderingArcrole(arcrole) and not euRenderingArcFound:
                                     baseSetKeys.append(("EU-rendering", None, None, None)) 
                                     baseSetKeys.append(("EU-rendering", linkrole, None, None)) 
                                     euRenderingArcFound = True
                                     self.modelXbrl.hasEuRendering = True
                                 for baseSetKey in baseSetKeys:
                                     self.modelXbrl.baseSets[baseSetKey].append(modelLink)
                                 arcrolesFound.add(arcrole)
                         elif xlinkType == "resource": 
                             # create resource and make accessible by id for document
                             modelResource = ModelObject.createResource(self, linkElement)
                         if modelResource is not None:
                             if linkElement.hasAttribute("id"):
                                 self.idObjects[linkElement.getAttribute("id")] = modelResource
                             modelLink.labeledResources[linkElement.getAttributeNS(XbrlConst.xlink, "label")] \
                                 .append(modelResource)
                         else:
                             XmlUtil.markIdAttributes(linkElement)
Ejemplo n.º 22
0
def checkDTS(val, modelDocument, visited):
    global targetNamespaceDatePattern, efmFilenamePattern, roleTypePattern, arcroleTypePattern, \
            arcroleDefinitionPattern, namePattern, linkroleDefinitionBalanceIncomeSheet, \
            namespacesConflictPattern
    if targetNamespaceDatePattern is None:
        targetNamespaceDatePattern = re.compile(r"/([12][0-9]{3})-([01][0-9])-([0-3][0-9])|"
                                            r"/([12][0-9]{3})([01][0-9])([0-3][0-9])|")
        efmFilenamePattern = re.compile(r"^[a-z0-9][a-zA-Z0-9_\.\-]*(\.xsd|\.xml)$")
        roleTypePattern = re.compile(r"^.*/role/[^/\s]+$")
        arcroleTypePattern = re.compile(r"^.*/arcrole/[^/\s]+$")
        arcroleDefinitionPattern = re.compile(r"^.*[^\\s]+.*$")  # at least one non-whitespace character
        namePattern = re.compile("[][()*+?\\\\/^{}|@#%^=~`\"';:,<>&$\u00a3\u20ac]") # u20ac=Euro, u00a3=pound sterling 
        linkroleDefinitionBalanceIncomeSheet = re.compile(r"[^-]+-\s+Statement\s+-\s+.*(income|balance|financial\W+position)",
                                                          re.IGNORECASE)
        namespacesConflictPattern = re.compile(r"http://(xbrl\.us|fasb\.org|xbrl\.sec\.gov)/(dei|us-types|us-roles|rr)/([0-9]{4}-[0-9]{2}-[0-9]{2})$")
    nonDomainItemNameProblemPattern = re.compile(
        r"({0})|(FirstQuarter|SecondQuarter|ThirdQuarter|FourthQuarter|[1-4]Qtr|Qtr[1-4]|ytd|YTD|HalfYear)(?:$|[A-Z\W])"
        .format(re.sub(r"\W", "", (val.entityRegistrantName or "").title())))
    
        
    visited.append(modelDocument)
    definesLabelLinkbase = False
    for referencedDocument, modelDocumentReference in modelDocument.referencesDocument.items():
        #6.07.01 no includes
        if modelDocumentReference.referenceType == "include":
            val.modelXbrl.error(("EFM.6.07.01", "GFM.1.03.01", "SBR.NL.2.2.0.18"),
                _("Taxonomy schema %(schema)s includes %(include)s, only import is allowed"),
                modelObject=modelDocumentReference.referringModelObject,
                    schema=os.path.basename(modelDocument.uri), 
                    include=os.path.basename(referencedDocument.uri))
        if referencedDocument not in visited:
            checkDTS(val, referencedDocument, visited)
            
    if val.disclosureSystem.standardTaxonomiesDict is None:
        pass

    if val.validateEFM: 
        if modelDocument.uri in val.disclosureSystem.standardTaxonomiesDict:
            if modelDocument.targetNamespace:
                # check for duplicates of us-types, dei, and rr taxonomies
                match = namespacesConflictPattern.match(modelDocument.targetNamespace)
                if match is not None:
                    val.standardNamespaceConflicts[match.group(2)].add(modelDocument)
        else:
            if len(modelDocument.basename) > 32:
                val.modelXbrl.error("EFM.5.01.01.tooManyCharacters",
                    _("Document file name %(filename)s must not exceed 32 characters."),
                    modelObject=modelDocument, filename=modelDocument.basename)
            if not efmFilenamePattern.match(modelDocument.basename):
                val.modelXbrl.error("EFM.5.01.01",
                    _("Document file name %(filename)s must start with a-z or 0-9, contain upper or lower case letters, ., -, _, and end with .xsd or .xml."),
                    modelObject=modelDocument, filename=modelDocument.basename)
    
    if (modelDocument.type == ModelDocument.Type.SCHEMA and 
        modelDocument.targetNamespace not in val.disclosureSystem.baseTaxonomyNamespaces and
        modelDocument.uri.startswith(val.modelXbrl.uriDir)):
        
        # check schema contents types
        if val.validateSBRNL:
            definesLinkroles = False
            definesArcroles = False
            definesLinkParts = False
            definesAbstractItems = False
            definesNonabstractItems = False
            definesConcepts = False
            definesTuples = False
            definesPresentationTuples = False
            definesSpecificationTuples = False
            definesTypes = False
            definesEnumerations = False
            definesDimensions = False
            definesDomains = False
            definesHypercubes = False
                
        # 6.7.3 check namespace for standard authority
        targetNamespaceAuthority = UrlUtil.authority(modelDocument.targetNamespace) 
        if targetNamespaceAuthority in val.disclosureSystem.standardAuthorities:
            val.modelXbrl.error(("EFM.6.07.03", "GFM.1.03.03"),
                _("Taxonomy schema %(schema)s namespace %(targetNamespace)s is a disallowed authority"),
                modelObject=modelDocument, schema=os.path.basename(modelDocument.uri), targetNamespace=modelDocument.targetNamespace, 
                targetNamespaceAuthority=UrlUtil.authority(modelDocument.targetNamespace, includeScheme=False))
            
        # 6.7.4 check namespace format
        if modelDocument.targetNamespace is None or not modelDocument.targetNamespace.startswith("http://"):
            match = None
        elif val.validateEFMorGFM:
            targetNamespaceDate = modelDocument.targetNamespace[len(targetNamespaceAuthority):]
            match = targetNamespaceDatePattern.match(targetNamespaceDate)
        else:
            match = None
        if match is not None:
            try:
                if match.lastindex == 3:
                    date = datetime.date(int(match.group(1)),int(match.group(2)),int(match.group(3)))
                elif match.lastindex == 6:
                    date = datetime.date(int(match.group(4)),int(match.group(5)),int(match.group(6)))
                else:
                    match = None
            except ValueError:
                match = None
        if match is None:
            val.modelXbrl.error(("EFM.6.07.04", "GFM.1.03.04"),
                _("Taxonomy schema %(schema)s namespace %(targetNamespace)s must have format http://{authority}/{versionDate}"),
                modelObject=modelDocument, schema=os.path.basename(modelDocument.uri), targetNamespace=modelDocument.targetNamespace)
        elif val.fileNameDate and date > val.fileNameDate:
            val.modelXbrl.info(("EFM.6.07.06", "GFM.1.03.06"),
                _("Warning: Taxonomy schema %(schema)s namespace %(targetNamespace)s has date later than document name date %(docNameDate)s"),
                modelObject=modelDocument, schema=os.path.basename(modelDocument.uri), targetNamespace=modelDocument.targetNamespace,
                docNameDate=val.fileNameDate)

        if modelDocument.targetNamespace is not None:
            # 6.7.5 check prefix for _
            authority = UrlUtil.authority(modelDocument.targetNamespace)
            if not re.match(r"(http://|https://|ftp://|urn:)\w+",authority):
                val.modelXbrl.error(("EFM.6.07.05", "GFM.1.03.05"),
                    _("Taxonomy schema %(schema)s namespace %(targetNamespace)s must be a valid URL with a valid authority for the namespace."),
                    modelObject=modelDocument, schema=os.path.basename(modelDocument.uri), targetNamespace=modelDocument.targetNamespace)
            prefix = XmlUtil.xmlnsprefix(modelDocument.xmlRootElement,modelDocument.targetNamespace)
            if not prefix:
                val.modelXbrl.error(("EFM.6.07.07", "GFM.1.03.07"),
                    _("Taxonomy schema %(schema)s namespace %(targetNamespace)s missing prefix for the namespace."),
                    modelObject=modelDocument, schema=os.path.basename(modelDocument.uri), targetNamespace=modelDocument.targetNamespace)
            elif "_" in prefix:
                val.modelXbrl.error(("EFM.6.07.07", "GFM.1.03.07"),
                    _("Taxonomy schema %(schema)s namespace %(targetNamespace)s prefix %(prefix)s must not have an '_'"),
                    modelObject=modelDocument, schema=os.path.basename(modelDocument.uri), targetNamespace=modelDocument.targetNamespace, prefix=prefix)

            if val.validateSBRNL:
                genrlSpeclRelSet = val.modelXbrl.relationshipSet(XbrlConst.generalSpecial)
            for modelConcept in modelDocument.xmlRootElement.iterdescendants(tag="{http://www.w3.org/2001/XMLSchema}element"):
                if isinstance(modelConcept,ModelConcept):
                    # 6.7.16 name not duplicated in standard taxonomies
                    name = modelConcept.get("name")
                    if name is None: 
                        name = ""
                        if modelConcept.get("ref") is not None:
                            continue    # don't validate ref's here
                    for c in val.modelXbrl.nameConcepts.get(name, []):
                        if c.modelDocument != modelDocument:
                            if (val.validateEFMorGFM and
                                  not c.modelDocument.uri.startswith(val.modelXbrl.uriDir)):
                                val.modelXbrl.error(("EFM.6.07.16", "GFM.1.03.18"),
                                    _("Concept %(concept)s is also defined in standard taxonomy schema schema %(standardSchema)s"),
                                    modelObject=(modelConcept,c), concept=modelConcept.qname, standardSchema=os.path.basename(c.modelDocument.uri), standardConcept=c.qname)
                            elif val.validateSBRNL:
                                if not (genrlSpeclRelSet.isRelated(modelConcept, "child", c) or genrlSpeclRelSet.isRelated(c, "child", modelConcept)):
                                    val.modelXbrl.error("SBR.NL.2.2.2.02",
                                        _("Concept %(concept)s is also defined in standard taxonomy schema %(standardSchema)s without a general-special relationship"),
                                        modelObject=c, concept=modelConcept.qname, standardSchema=os.path.basename(c.modelDocument.uri))
                    ''' removed RH 2011-12-23 corresponding set up of table in ValidateFiling
                    if val.validateSBRNL and name in val.nameWordsTable:
                        if not any( any( genrlSpeclRelSet.isRelated(c, "child", modelConcept)
                                         for c in val.modelXbrl.nameConcepts.get(partialWordName, []))
                                    for partialWordName in val.nameWordsTable[name]):
                            val.modelXbrl.error("SBR.NL.2.3.2.01",
                                _("Concept %(specialName)s is appears to be missing a general-special relationship to %(generalNames)s"),
                                modelObject=c, specialName=modelConcept.qname, generalNames=', or to '.join(val.nameWordsTable[name]))
                    '''

                    # 6.7.17 id properly formed
                    id = modelConcept.id
                    requiredId = (prefix if prefix is not None else "") + "_" + name
                    if val.validateEFMorGFM and id != requiredId:
                        val.modelXbrl.error(("EFM.6.07.17", "GFM.1.03.19"),
                            _("Concept %(concept)s id %(id)s should be %(requiredId)s"),
                            modelObject=modelConcept, concept=modelConcept.qname, id=id, requiredId=requiredId)
                        
                    # 6.7.18 nillable is true
                    nillable = modelConcept.get("nillable")
                    if nillable != "true" and modelConcept.isItem:
                        val.modelXbrl.error(("EFM.6.07.18", "GFM.1.03.20"),
                            _("Taxonomy schema %(schema)s element %(concept)s nillable %(nillable)s should be 'true'"),
                            modelObject=modelConcept, schema=os.path.basename(modelDocument.uri),
                            concept=name, nillable=nillable)
        
                    # 6.7.19 not tuple
                    if modelConcept.isTuple:
                        if val.validateEFMorGFM:
                            val.modelXbrl.error(("EFM.6.07.19", "GFM.1.03.21"),
                                _("Concept %(concept)s is a tuple"),
                                modelObject=modelConcept, concept=modelConcept.qname)
                        
                    # 6.7.20 no typed domain ref
                    if modelConcept.isTypedDimension:
                        val.modelXbrl.error(("EFM.6.07.20", "GFM.1.03.22"),
                            _("Concept %(concept)s has typedDomainRef %(typedDomainRef)s"),
                            modelObject=modelConcept, concept=modelConcept.qname,
                            typedDomainRef=modelConcept.typedDomainElement.qname if modelConcept.typedDomainElement is not None else modelConcept.typedDomainRef)
                        
                    # 6.7.21 abstract must be duration
                    isDuration = modelConcept.periodType == "duration"
                    if modelConcept.isAbstract and not isDuration:
                        val.modelXbrl.error(("EFM.6.07.21", "GFM.1.03.23"),
                            _("Taxonomy schema %(schema)s element %(concept)s is abstract but period type is not duration"),
                            modelObject=modelConcept, schema=os.path.basename(modelDocument.uri), concept=modelConcept.qname)
                        
                    # 6.7.22 abstract must be stringItemType
                    ''' removed SEC EFM v.17, Edgar release 10.4, and GFM 2011-04-08
                    if modelConcept.abstract == "true" and modelConcept.typeQname != XbrlConst. qnXbrliStringItemType:
                        val.modelXbrl.error(("EFM.6.07.22", "GFM.1.03.24"),
                            _("Concept %(concept)s  is abstract but type is not xbrli:stringItemType"),
                            modelObject=modelConcept, concept=modelConcept.qname)
					'''
                    substititutionGroupQname = modelConcept.substitutionGroupQname
                    # 6.7.23 Axis must be subs group dimension
                    if name.endswith("Axis") ^ (substititutionGroupQname == XbrlConst.qnXbrldtDimensionItem):
                        val.modelXbrl.error(("EFM.6.07.23", "GFM.1.03.25"),
                            _("Concept %(concept)s must end in Axis to be in xbrldt:dimensionItem substitution group"),
                            modelObject=modelConcept, concept=modelConcept.qname)

                    # 6.7.24 Table must be subs group hypercube
                    if name.endswith("Table") ^ (substititutionGroupQname == XbrlConst.qnXbrldtHypercubeItem):
                        val.modelXbrl.error(("EFM.6.07.24", "GFM.1.03.26"),
                            _("Concept %(concept)s must end in Table to be in xbrldt:hypercubeItem substitution group"),
                            modelObject=modelConcept, schema=os.path.basename(modelDocument.uri), concept=modelConcept.qname)

                    # 6.7.25 if neither hypercube or dimension, substitution group must be item
                    if substititutionGroupQname not in (None,
                                                        XbrlConst.qnXbrldtDimensionItem, 
                                                        XbrlConst.qnXbrldtHypercubeItem,
                                                        XbrlConst.qnXbrliItem):                           
                        val.modelXbrl.error(("EFM.6.07.25", "GFM.1.03.27"),
                            _("Concept %(concept)s has disallowed substitution group %(substitutionGroup)s"),
                            modelObject=modelConcept, concept=modelConcept.qname,
                            substitutionGroup=modelConcept.substitutionGroupQname)
                        
                    # 6.7.26 Table must be subs group hypercube
                    if name.endswith("LineItems") and modelConcept.abstract != "true":
                        val.modelXbrl.error(("EFM.6.07.26", "GFM.1.03.28"),
                            _("Concept %(concept)s is a LineItems but not abstract"),
                            modelObject=modelConcept, concept=modelConcept.qname)

                    # 6.7.27 type domainMember must end with Domain or Member
                    conceptType = modelConcept.type
                    isDomainItemType = conceptType is not None and conceptType.isDomainItemType
                    endsWithDomainOrMember = name.endswith("Domain") or name.endswith("Member")
                    if isDomainItemType != endsWithDomainOrMember:
                        val.modelXbrl.error(("EFM.6.07.27", "GFM.1.03.29"),
                            _("Concept %(concept)s must end with Domain or Member for type of domainItemType"),
                            modelObject=modelConcept, concept=modelConcept.qname)

                    # 6.7.28 domainItemType must be duration
                    if isDomainItemType and not isDuration:
                        val.modelXbrl.error(("EFM.6.07.28", "GFM.1.03.30"),
                            _("Concept %(concept)s is a domainItemType and must be periodType duration"),
                            modelObject=modelConcept, concept=modelConcept.qname)
                                                
                    #6.7.31 (version 27) fractions
                    if modelConcept.isFraction:
                        val.modelXbrl.error("EFM.6.07.31",
                            _("Concept %(concept)s is a fraction"),
                            modelObject=modelConcept, concept=modelConcept.qname)
    
                    #6.7.32 (version 27) instant non numeric
                    if modelConcept.isItem and (not modelConcept.isNumeric and not isDuration and not modelConcept.isAbstract and not isDomainItemType):
                        val.modelXbrl.error("EFM.6.07.32",
                            _("Taxonomy schema %(schema)s element %(concept)s is non-numeric but period type is not duration"),
                            modelObject=modelConcept, schema=os.path.basename(modelDocument.uri), concept=modelConcept.qname)
                        
                    # 6.8.5 semantic check, check LC3 name
                    if name:
                        if not name[0].isupper():
                            val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.05.firstLetter", "GFM.2.03.05.firstLetter"),
                                _("Concept %(concept)s name must start with a capital letter"),
                                modelObject=modelConcept, concept=modelConcept.qname)
                        if namePattern.search(name):
                            val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.05.disallowedCharacter", "GFM.2.03.05.disallowedCharacter"),
                                _("Concept %(concept)s has disallowed name character"),
                                modelObject=modelConcept, concept=modelConcept.qname)
                        if len(name) > 200:
                            val.modelXbrl.log("ERROR-SEMANTIC", "EFM.6.08.05.nameLength",
                                _("Concept %(concept)s name length %(namelength)s exceeds 200 characters"),
                                modelObject=modelConcept, concept=modelConcept.qname, namelength=len(name))
                        
                    if val.validateEFM:
                        label = modelConcept.label(lang="en-US", fallbackToQname=False)
                        if label:
                            # allow Joe's Bar, N.A.  to be JoesBarNA -- remove ', allow A. as not article "a"
                            lc3name = ''.join(re.sub(r"['.-]", "", (w[0] or w[2] or w[3] or w[4])).title()
                                              for w in re.findall(r"((\w+')+\w+)|(A[.-])|([.-]A(?=\W|$))|(\w+)", label) # EFM implies this should allow - and . re.findall(r"[\w\-\.]+", label)
                                              if w[4].lower() not in ("the", "a", "an"))
                            if not(name == lc3name or 
                                   (name and lc3name and lc3name[0].isdigit() and name[1:] == lc3name and (name[0].isalpha() or name[0] == '_'))):
                                val.modelXbrl.log("WARNING-SEMANTIC", "EFM.6.08.05.LC3",
                                    _("Concept %(concept)s should match expected LC3 composition %(lc3name)s"),
                                    modelObject=modelConcept, concept=modelConcept.qname, lc3name=lc3name)
                                
                    if conceptType is not None:
                        # 6.8.6 semantic check
                        if not isDomainItemType and conceptType.qname != XbrlConst.qnXbrliDurationItemType:
                            nameProblems = nonDomainItemNameProblemPattern.findall(name)
                            if any(any(t) for t in nameProblems):  # list of tuples with possibly nonempty strings
                                val.modelXbrl.log("WARNING-SEMANTIC", ("EFM.6.08.06", "GFM.2.03.06"),
                                    _("Concept %(concept)s should not contain company or period information, found: %(matches)s"),
                                    modelObject=modelConcept, concept=modelConcept.qname, 
                                    matches=", ".join(''.join(t) for t in nameProblems))
                        
                        if conceptType.qname == XbrlConst.qnXbrliMonetaryItemType:
                            if not modelConcept.balance:
                                # 6.8.11 may not appear on a income or balance statement
                                if any(linkroleDefinitionBalanceIncomeSheet.match(roleType.definition)
                                       for rel in val.modelXbrl.relationshipSet(XbrlConst.parentChild).toModelObject(modelConcept)
                                       for roleType in val.modelXbrl.roleTypes.get(rel.linkrole,())):
                                    val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.11", "GFM.2.03.11"),
                                        _("Concept %(concept)s must have a balance because it appears in a statement of income or balance sheet"),
                                        modelObject=modelConcept, concept=modelConcept.qname)
                                # 6.11.5 semantic check, must have a documentation label
                                stdLabel = modelConcept.label(lang="en-US", fallbackToQname=False)
                                defLabel = modelConcept.label(preferredLabel=XbrlConst.documentationLabel, lang="en-US", fallbackToQname=False)
                                if not defLabel or ( # want different words than std label
                                    stdLabel and re.findall(r"\w+", stdLabel) == re.findall(r"\w+", defLabel)):
                                    val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.11.05", "GFM.2.04.04"),
                                        _("Concept %(concept)s is monetary without a balance and must have a documentation label that disambiguates its sign"),
                                        modelObject=modelConcept, concept=modelConcept.qname)
                        
                        # 6.8.16 semantic check
                        if conceptType.qname == XbrlConst.qnXbrliDateItemType and modelConcept.periodType != "duration":
                            val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.16", "GFM.2.03.16"),
                                _("Concept %(concept)s of type xbrli:dateItemType must have periodType duration"),
                                modelObject=modelConcept, concept=modelConcept.qname)
                        
                        # 6.8.17 semantic check
                        if conceptType.qname == XbrlConst.qnXbrliStringItemType and modelConcept.periodType != "duration":
                            val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.17", "GFM.2.03.17"),
                                _("Concept %(concept)s of type xbrli:stringItemType must have periodType duration"),
                                modelObject=modelConcept, concept=modelConcept.qname)
                        
                    if val.validateSBRNL:
                        if modelConcept.isTuple:
                            if modelConcept.substitutionGroupQname.localName == "presentationTuple" and modelConcept.substitutionGroupQname.namespaceURI.endswith("/basis/sbr/xbrl/xbrl-syntax-extension"): # namespace may change each year
                                definesPresentationTuples = True
                            elif modelConcept.substitutionGroupQname.localName == "specificationTuple" and modelConcept.substitutionGroupQname.namespaceURI.endswith("/basis/sbr/xbrl/xbrl-syntax-extension"): # namespace may change each year
                                definesSpecificationTuples = True
                            else:
                                definesTuples = True
                            definesConcepts = True
                            if modelConcept.isAbstract:
                                val.modelXbrl.error("SBR.NL.2.2.2.03",
                                    _("Concept %(concept)s is an abstract tuple"),
                                    modelObject=modelConcept, concept=modelConcept.qname)
                            if tupleCycle(val,modelConcept):
                                val.modelXbrl.error("SBR.NL.2.2.2.07",
                                    _("Tuple %(concept)s has a tuple cycle"),
                                    modelObject=modelConcept, concept=modelConcept.qname)
                            if modelConcept.get("nillable") != "false" and modelConcept.isRoot:
                                val.modelXbrl.error("SBR.NL.2.2.2.17", #don't want default, just what was really there
                                    _("Tuple %(concept)s must have nillable='false'"),
                                    modelObject=modelConcept, concept=modelConcept.qname)
                        elif modelConcept.isItem:
                            definesConcepts = True
                        if modelConcept.abstract == "true":
                            if modelConcept.isRoot:
                                if modelConcept.get("nillable") != "false": #don't want default, just what was really there
                                    val.modelXbrl.error("SBR.NL.2.2.2.16",
                                        _("Abstract root concept %(concept)s must have nillable='false'"),
                                    modelObject=modelConcept, concept=modelConcept.qname)
                                if modelConcept.typeQname != XbrlConst.qnXbrliStringItemType:
                                    val.modelXbrl.error("SBR.NL.2.2.2.21",
                                        _("Abstract root concept %(concept)s must have type='xbrli:stringItemType'"),
                                    modelObject=modelConcept, concept=modelConcept.qname)
                            if modelConcept.balance:
                                val.modelXbrl.error("SBR.NL.2.2.2.22",
                                    _("Abstract concept %(concept)s must not have a balance attribute"),
                                    modelObject=modelConcept, concept=modelConcept.qname)
                            if modelConcept.isHypercubeItem:
                                definesHypercubes = True
                            elif modelConcept.isDimensionItem:
                                definesDimensions = True
                            elif substititutionGroupQname and substititutionGroupQname.localName in ("domainItem","domainMemberItem"):
                                definesDomains = True
                            elif modelConcept.isItem:
                                definesAbstractItems = True
                        else:   # not abstract
                            if modelConcept.isItem:
                                definesNonabstractItems = True
                                if not (modelConcept.label(preferredLabel=XbrlConst.documentationLabel,fallbackToQname=False,lang="nl") or
                                        val.modelXbrl.relationshipSet(XbrlConst.conceptReference).fromModelObject(c) or
                                        modelConcept.genLabel(role=XbrlConst.genDocumentationLabel,lang="nl") or
                                        val.modelXbrl.relationshipSet(XbrlConst.elementReference).fromModelObject(c)):
                                    val.modelXbrl.error("SBR.NL.2.2.2.28",
                                        _("Concept %(concept)s must have a documentation label or reference"),
                                        modelObject=modelConcept, concept=modelConcept.qname)
                        if modelConcept.balance and not modelConcept.instanceOfType(XbrlConst.qnXbrliMonetaryItemType):
                            val.modelXbrl.error("SBR.NL.2.2.2.24",
                                _("Non-monetary concept %(concept)s must not have a balance attribute"),
                                modelObject=modelConcept, concept=modelConcept.qname)
                        if modelConcept.isLinkPart:
                            definesLinkParts = True
                            val.modelXbrl.error("SBR.NL.2.2.5.01",
                                _("Link:part concept %(concept)s is not allowed"),
                                modelObject=modelConcept, concept=modelConcept.qname)
                            if not modelConcept.genLabel(fallbackToQname=False,lang="nl"):
                                val.modelXbrl.error("SBR.NL.2.2.5.02",
                                    _("Link part definition %(concept)s must have a generic label in language 'nl'"),
                                    modelObject=modelConcept, concept=modelConcept.qname)
        # 6.7.8 check for embedded linkbase
        for e in modelDocument.xmlRootElement.iterdescendants(tag="{http://www.xbrl.org/2003/linkbase}linkbase"):
            if isinstance(e,ModelObject):
                val.modelXbrl.error(("EFM.6.07.08", "GFM.1.03.08"),
                    _("Taxonomy schema %(schema)s contains an embedded linkbase"),
                    modelObject=e, schema=modelDocument.basename)
                break

        requiredUsedOns = {XbrlConst.qnLinkPresentationLink,
                           XbrlConst.qnLinkCalculationLink,
                           XbrlConst.qnLinkDefinitionLink}
        
        standardUsedOns = {XbrlConst.qnLinkLabel, XbrlConst.qnLinkReference, 
                           XbrlConst.qnLinkDefinitionArc, XbrlConst.qnLinkCalculationArc, XbrlConst.qnLinkPresentationArc, 
                           XbrlConst.qnLinkLabelArc, XbrlConst.qnLinkReferenceArc, 
                           # per WH, private footnote arc and footnore resource roles are not allowed
                           XbrlConst.qnLinkFootnoteArc, XbrlConst.qnLinkFootnote,
                           }

        # 6.7.9 role types authority
        for e in modelDocument.xmlRootElement.iterdescendants(tag="{http://www.xbrl.org/2003/linkbase}roleType"):
            if isinstance(e,ModelObject):
                roleURI = e.get("roleURI")
                if targetNamespaceAuthority != UrlUtil.authority(roleURI):
                    val.modelXbrl.error(("EFM.6.07.09", "GFM.1.03.09"),
                        _("RoleType %(roleType)s does not match authority %(targetNamespaceAuthority)s"),
                        modelObject=e, roleType=roleURI, targetNamespaceAuthority=targetNamespaceAuthority, targetNamespace=modelDocument.targetNamespace)
                # 6.7.9 end with .../role/lc3 name
                if not roleTypePattern.match(roleURI):
                    val.modelXbrl.warning(("EFM.6.07.09.roleEnding", "GFM.1.03.09"),
                        "RoleType %(roleType)s should end with /role/{LC3name}",
                        modelObject=e, roleType=roleURI)
                    
                # 6.7.10 only one role type declaration in DTS
                modelRoleTypes = val.modelXbrl.roleTypes.get(roleURI)
                if modelRoleTypes is not None:
                    modelRoleType = modelRoleTypes[0]
                    definition = modelRoleType.definitionNotStripped
                    usedOns = modelRoleType.usedOns
                    if len(modelRoleTypes) == 1:
                        # 6.7.11 used on's for pre, cal, def if any has a used on
                        if not usedOns.isdisjoint(requiredUsedOns) and len(requiredUsedOns - usedOns) > 0:
                            val.modelXbrl.error(("EFM.6.07.11", "GFM.1.03.11"),
                                _("RoleType %(roleType)s missing used on %(usedOn)s"),
                                modelObject=e, roleType=roleURI, usedOn=requiredUsedOns - usedOns)
                            
                        # 6.7.12 definition match pattern
                        if (val.disclosureSystem.roleDefinitionPattern is not None and
                            (definition is None or not val.disclosureSystem.roleDefinitionPattern.match(definition))):
                            val.modelXbrl.error(("EFM.6.07.12", "GFM.1.03.12-14"),
                                _("RoleType %(roleType)s definition \"%(definition)s\" must match {Sortcode} - {Type} - {Title}"),
                                modelObject=e, roleType=roleURI, definition=(definition or ""))

                    if usedOns & standardUsedOns: # semantics check
                        val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.03", "GFM.2.03.03"),
                            _("RoleType %(roleuri)s is defined using role types already defined by standard roles for: %(qnames)s"),
                            modelObject=e, roleuri=roleURI, qnames=', '.join(str(qn) for qn in usedOns & standardUsedOns))

                    if val.validateSBRNL:
                        if usedOns & XbrlConst.standardExtLinkQnames or XbrlConst.qnGenLink in usedOns:
                            definesLinkroles = True
                            if not e.genLabel():
                                val.modelXbrl.error("SBR.NL.2.2.3.03",
                                    _("Link RoleType %(roleType)s missing a generic standard label"),
                                    modelObject=e, roleType=roleURI)
                            nlLabel = e.genLabel(lang="nl")
                            if definition != nlLabel:
                                val.modelXbrl.error("SBR.NL.2.2.3.04",
                                    _("Link RoleType %(roleType)s definition does not match NL standard generic label, \ndefinition: %(definition)s \nNL label: %(label)s"),
                                    modelObject=e, roleType=roleURI, definition=definition, label=nlLabel)
                        if definition and (definition[0].isspace() or definition[-1].isspace()):
                            val.modelXbrl.error("SBR.NL.2.2.3.07",
                                _('Link RoleType %(roleType)s definition has leading or trailing spaces: "%(definition)s"'),
                                modelObject=e, roleType=roleURI, definition=definition)

        # 6.7.13 arcrole types authority
        for e in modelDocument.xmlRootElement.iterdescendants(tag="{http://www.xbrl.org/2003/linkbase}arcroleType"):
            if isinstance(e,ModelObject):
                arcroleURI = e.get("arcroleURI")
                if targetNamespaceAuthority != UrlUtil.authority(arcroleURI):
                    val.modelXbrl.error(("EFM.6.07.13", "GFM.1.03.15"),
                        _("ArcroleType %(arcroleType)s does not match authority %(targetNamespaceAuthority)s"),
                        modelObject=e, arcroleType=arcroleURI, targetNamespaceAuthority=targetNamespaceAuthority, targetNamespace=modelDocument.targetNamespace)
                # 6.7.13 end with .../arcrole/lc3 name
                if not arcroleTypePattern.match(arcroleURI):
                    val.modelXbrl.warning(("EFM.6.07.13.arcroleEnding", "GFM.1.03.15"),
                        _("ArcroleType %(arcroleType)s should end with /arcrole/{LC3name}"),
                        modelObject=e, arcroleType=arcroleURI)
                    
                # 6.7.15 definition match pattern
                modelRoleTypes = val.modelXbrl.arcroleTypes[arcroleURI]
                definition = modelRoleTypes[0].definition
                if definition is None or not arcroleDefinitionPattern.match(definition):
                    val.modelXbrl.error(("EFM.6.07.15", "GFM.1.03.17"),
                        _("ArcroleType %(arcroleType)s definition must be non-empty"),
                        modelObject=e, arcroleType=arcroleURI)
    
                # semantic checks
                usedOns = modelRoleTypes[0].usedOns
                if usedOns & standardUsedOns: # semantics check
                    val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.03", "GFM.2.03.03"),
                        _("ArcroleType %(arcroleuri)s is defined using role types already defined by standard arcroles for: %(qnames)s"),
                        modelObject=e, arcroleuri=arcroleURI, qnames=', '.join(str(qn) for qn in usedOns & standardUsedOns))

                if val.validateSBRNL:
                    definesArcroles = True
                    val.modelXbrl.error("SBR.NL.2.2.4.01",
                        _("Arcrole type definition is not allowed: %(arcroleURI)s"),
                        modelObject=e, arcroleURI=arcroleURI)
                    
        if val.validateSBRNL:
            for appinfoElt in modelDocument.xmlRootElement.iter(tag="{http://www.w3.org/2001/XMLSchema}appinfo"):
                for nonLinkElt in appinfoElt.iterdescendants():
                    if isinstance(nonLinkElt, ModelObject) and nonLinkElt.namespaceURI != XbrlConst.link:
                        val.modelXbrl.error("SBR.NL.2.2.11.05",
                            _("Appinfo contains disallowed non-link element %(element)s"),
                            modelObject=nonLinkElt, element=nonLinkElt.qname)

            for cplxTypeElt in modelDocument.xmlRootElement.iter(tag="{http://www.w3.org/2001/XMLSchema}complexType"):
                choiceElt = cplxTypeElt.find("{http://www.w3.org/2001/XMLSchema}choice")
                if choiceElt is not None:
                    val.modelXbrl.error("SBR.NL.2.2.11.09",
                        _("ComplexType contains disallowed xs:choice element"),
                        modelObject=choiceElt)
                    
            for cplxContentElt in modelDocument.xmlRootElement.iter(tag="{http://www.w3.org/2001/XMLSchema}complexContent"):
                if XmlUtil.descendantAttr(cplxContentElt, "http://www.w3.org/2001/XMLSchema", ("extension","restriction"), "base") != "sbr:placeholder":
                    val.modelXbrl.error("SBR.NL.2.2.11.10",
                        _("ComplexContent is disallowed"),
                        modelObject=cplxContentElt)

            definesTypes = (modelDocument.xmlRootElement.find("{http://www.w3.org/2001/XMLSchema}complexType") is not None or
                            modelDocument.xmlRootElement.find("{http://www.w3.org/2001/XMLSchema}simpleType") is not None)
            
            for enumElt in modelDocument.xmlRootElement.iter(tag="{http://www.w3.org/2001/XMLSchema}enumeration"):
                definesEnumerations = True
                if any(not valueElt.genLabel(lang="nl")
                       for valueElt in enumElt.iter(tag="{http://www.w3.org/2001/XMLSchema}value")):
                    val.modelXbrl.error("SBR.NL.2.2.7.05",
                        _("Enumeration element has value(s) without generic label."),
                        modelObject=enumElt)

            if (definesLinkroles + definesArcroles + definesLinkParts +
                definesAbstractItems + definesNonabstractItems + 
                definesTuples + definesPresentationTuples + definesSpecificationTuples + definesTypes +
                definesEnumerations + definesDimensions + definesDomains + 
                definesHypercubes) != 1:
                schemaContents = []
                if definesLinkroles: schemaContents.append(_("linkroles"))
                if definesArcroles: schemaContents.append(_("arcroles"))
                if definesLinkParts: schemaContents.append(_("link parts"))
                if definesAbstractItems: schemaContents.append(_("abstract items"))
                if definesNonabstractItems: schemaContents.append(_("nonabstract items"))
                if definesTuples: schemaContents.append(_("tuples"))
                if definesPresentationTuples: schemaContents.append(_("sbrPresentationTuples"))
                if definesSpecificationTuples: schemaContents.append(_("sbrSpecificationTuples"))
                if definesTypes: schemaContents.append(_("types"))
                if definesEnumerations: schemaContents.append(_("enumerations"))
                if definesDimensions: schemaContents.append(_("dimensions"))
                if definesDomains: schemaContents.append(_("domains"))
                if definesHypercubes: schemaContents.append(_("hypercubes"))
                if schemaContents:
                    if not ((definesTuples or definesPresentationTuples or definesSpecificationTuples) and
                            not (definesLinkroles or definesArcroles or definesLinkParts or definesAbstractItems or
                                 definesTypes or definesDimensions or definesDomains or definesHypercubes)):
                        val.modelXbrl.error("SBR.NL.2.2.1.01",
                            _("Taxonomy schema may only define one of these: %(contents)s"),
                            modelObject=modelDocument, contents=', '.join(schemaContents))
                elif not any(refDoc.inDTS and refDoc.targetNamespace not in val.disclosureSystem.baseTaxonomyNamespaces
                             for refDoc in modelDocument.referencesDocument.keys()): # no linkbase ref or includes
                    val.modelXbrl.error("SBR.NL.2.2.1.01",
                        _("Taxonomy schema must be a DTS entrypoint OR define linkroles OR arcroles OR link:parts OR context fragments OR abstract items OR tuples OR non-abstract elements OR types OR enumerations OR dimensions OR domains OR hypercubes"),
                        modelObject=modelDocument)
            if definesConcepts ^ any(  # xor so either concepts and no label LB or no concepts and has label LB
                       (refDoc.type == ModelDocument.Type.LINKBASE and
                        XmlUtil.descendant(refDoc.xmlRootElement, XbrlConst.link, "labelLink") is not None)
                       for refDoc in modelDocument.referencesDocument.keys()): # no label linkbase
                val.modelXbrl.error("SBR.NL.2.2.1.02",
                    _("A schema that defines concepts MUST have a linked 2.1 label linkbase"),
                    modelObject=modelDocument)
            if (definesNonabstractItems or definesTuples) and not any(  # was xor but changed to and not per RH 1/11/12
                       (refDoc.type == ModelDocument.Type.LINKBASE and
                       (XmlUtil.descendant(refDoc.xmlRootElement, XbrlConst.link, "referenceLink") is not None or
                        XmlUtil.descendant(refDoc.xmlRootElement, XbrlConst.link, "label", "{http://www.w3.org/1999/xlink}role", "http://www.xbrl.org/2003/role/documentation" ) is not None))
                        for refDoc in modelDocument.referencesDocument.keys()):
                val.modelXbrl.error("SBR.NL.2.2.1.03",
                    _("A schema that defines non-abstract items MUST have a linked (2.1) reference linkbase AND/OR a label linkbase with @xlink:role=documentation"),
                    modelObject=modelDocument)

        #6.3.3 filename check
        m = re.match(r"^\w+-([12][0-9]{3}[01][0-9][0-3][0-9]).xsd$", modelDocument.basename)
        if m:
            try: # check date value
                datetime.datetime.strptime(m.group(1),"%Y%m%d").date()
                # date and format are ok, check "should" part of 6.3.3
                if val.fileNameBasePart:
                    expectedFilename = "{0}-{1}.xsd".format(val.fileNameBasePart, val.fileNameDatePart)
                    if modelDocument.basename != expectedFilename:
                        val.modelXbrl.log("WARNING-SEMANTIC", ("EFM.6.03.03.matchInstance", "GFM.1.01.01.matchInstance"),
                            _('Schema file name warning: %(filename)s, should match %(expectedFilename)s'),
                            modelObject=modelDocument, filename=modelDocument.basename, expectedFilename=expectedFilename)
            except ValueError:
                val.modelXbrl.error((val.EFM60303, "GFM.1.01.01"),
                    _('Invalid schema file base name part (date) in "{base}-{yyyymmdd}.xsd": %(filename)s'),
                    modelObject=modelDocument, filename=modelDocument.basename,
                    messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))
        else:
            val.modelXbrl.error((val.EFM60303, "GFM.1.01.01"),
                _('Invalid schema file name, must match "{base}-{yyyymmdd}.xsd": %(filename)s'),
                modelObject=modelDocument, filename=modelDocument.basename,
                messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))

    elif modelDocument.type == ModelDocument.Type.LINKBASE:
        # if it is part of the submission (in same directory) check name
        labelRels = None
        if modelDocument.filepath.startswith(val.modelXbrl.modelDocument.filepathdir):
            #6.3.3 filename check
            extLinkElt = XmlUtil.descendant(modelDocument.xmlRootElement, XbrlConst.link, "*", "{http://www.w3.org/1999/xlink}type", "extended")
            if extLinkElt is None:# no ext link element
                val.modelXbrl.error((val.EFM60303 + ".noLinkElement", "GFM.1.01.01.noLinkElement"),
                    _('Invalid linkbase file name: %(filename)s, has no extended link element, cannot determine link type.'),
                    modelObject=modelDocument, filename=modelDocument.basename,
                    messageCodes=("EFM.6.03.03.noLinkElement", "EFM.6.23.01.noLinkElement",  "GFM.1.01.01.noLinkElement"))
            elif extLinkElt.localName not in extLinkEltFileNameEnding:
                val.modelXbrl.error("EFM.6.03.02",
                    _('Invalid linkbase link element %(linkElement)s in %(filename)s'),
                    modelObject=modelDocument, linkElement=extLinkElt.localName, filename=modelDocument.basename)
            else:
                m = re.match(r"^\w+-([12][0-9]{3}[01][0-9][0-3][0-9])(_[a-z]{3}).xml$", modelDocument.basename)
                expectedSuffix = extLinkEltFileNameEnding[extLinkElt.localName]
                if m and m.group(2) == expectedSuffix:
                    try: # check date value
                        datetime.datetime.strptime(m.group(1),"%Y%m%d").date()
                        # date and format are ok, check "should" part of 6.3.3
                        if val.fileNameBasePart:
                            expectedFilename = "{0}-{1}{2}.xml".format(val.fileNameBasePart, val.fileNameDatePart, expectedSuffix)
                            if modelDocument.basename != expectedFilename:
                                val.modelXbrl.log("WARNING-SEMANTIC", ("EFM.6.03.03.matchInstance", "GFM.1.01.01.matchInstance"),
                                    _('Linkbase name warning: %(filename)s should match %(expectedFilename)s'),
                                    modelObject=modelDocument, filename=modelDocument.basename, expectedFilename=expectedFilename)
                    except ValueError:
                        val.modelXbrl.error((val.EFM60303, "GFM.1.01.01"),
                            _('Invalid linkbase base file name part (date) in "{base}-{yyyymmdd}_{suffix}.xml": %(filename)s'),
                            modelObject=modelDocument, filename=modelDocument.basename,
                            messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))
                else:
                    val.modelXbrl.error((val.EFM60303, "GFM.1.01.01"),
                        _('Invalid linkbase name, must match "{base}-{yyyymmdd}%(expectedSuffix)s.xml": %(filename)s'),
                        modelObject=modelDocument, filename=modelDocument.basename, expectedSuffix=expectedSuffix,
                        messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))
                if extLinkElt.localName == "labelLink":
                    if labelRels is None:
                        labelRels = val.modelXbrl.relationshipSet(XbrlConst.conceptLabel)
                    for labelElt in XmlUtil.children(extLinkElt, XbrlConst.link, "label"):
                        # 6.10.9
                        if XbrlConst.isNumericRole(labelElt.role):
                            for rel in labelRels.toModelObject(labelElt):
                                if rel.fromModelObject is not None and not rel.fromModelObject.isNumeric:
                                    val.modelXbrl.error("EFM.6.10.09",
                                        _("Label of non-numeric concept %(concept)s has a numeric role: %(role)s"), 
                                          modelObject=(labelElt, rel.fromModelObject), concept=rel.fromModelObject.qname, role=labelElt.role)
    visited.remove(modelDocument)
Ejemplo n.º 23
0
 def view(self, firstTime=False):
     self.blockSelectEvent = 1
     self.blockViewModelObject = 0
     self.tag_has = defaultdict(list) # temporary until Tk 8.6
     # relationship set based on linkrole parameter, to determine applicable linkroles
     relationshipSet = self.modelXbrl.relationshipSet(self.arcrole, self.linkrole, self.linkqname, self.arcqname)
     if not relationshipSet:
         self.modelXbrl.modelManager.addToLog(_("no relationships for {0}").format(self.arcrole))
         return False
     
     if firstTime:
         # set up treeView widget and tabbed pane
         hdr = self.treeColHdr if self.treeColHdr else _("{0} Relationships").format(XbrlConst.baseSetArcroleLabel(self.arcrole)[1:])
         self.treeView.heading("#0", text=hdr)
         if self.arcrole == XbrlConst.parentChild: # extra columns
             self.treeView.column("#0", width=300, anchor="w")
             self.treeView["columns"] = ("type", "references")
             self.treeView.column("type", width=100, anchor="w", stretch=False)
             self.treeView.heading("type", text=_("Type"))
             self.treeView.column("references", width=200, anchor="w", stretch=False)
             self.treeView.heading("references", text=_("References"))
         elif self.arcrole == XbrlConst.summationItem: # extra columns
             self.treeView.column("#0", width=300, anchor="w")
             self.treeView["columns"] = ("weight", "balance")
             self.treeView.column("weight", width=48, anchor="w", stretch=False)
             self.treeView.heading("weight", text=_("Weight"))
             self.treeView.column("balance", width=70, anchor="w", stretch=False)
             self.treeView.heading("balance", text=_("Balance"))
         elif self.arcrole == "XBRL-dimensions":    # add columns for dimensional information
             self.treeView.column("#0", width=300, anchor="w")
             self.treeView["columns"] = ("arcrole", "contextElement", "closed", "usable")
             self.treeView.column("arcrole", width=100, anchor="w", stretch=False)
             self.treeView.heading("arcrole", text="Arcrole")
             self.treeView.column("contextElement", width=50, anchor="center", stretch=False)
             self.treeView.heading("contextElement", text="Context")
             self.treeView.column("closed", width=40, anchor="center", stretch=False)
             self.treeView.heading("closed", text="Closed")
             self.treeView.column("usable", width=40, anchor="center", stretch=False)
             self.treeView.heading("usable", text="Usable")
         elif self.arcrole == "Table-rendering":    # add columns for dimensional information
             self.treeView.column("#0", width=160, anchor="w")
             self.treeView["columns"] = ("axis", "abstract", "header", "priItem", "dims")
             self.treeView.column("axis", width=50, anchor="center", stretch=False)
             self.treeView.heading("axis", text="Axis")
             self.treeView.column("abstract", width=24, anchor="center", stretch=False)
             self.treeView.heading("abstract", text="Abs")
             self.treeView.column("header", width=160, anchor="w", stretch=False)
             self.treeView.heading("header", text="Header")
             self.treeView.column("priItem", width=100, anchor="w", stretch=False)
             self.treeView.heading("priItem", text="Primary Item")
             self.treeView.column("dims", width=150, anchor="w", stretch=False)
             self.treeView.heading("dims", text=_("Dimensions"))
     self.id = 1
     for previousNode in self.treeView.get_children(""): 
         self.treeView.delete(previousNode)
     # sort URIs by definition
     linkroleUris = []
     for linkroleUri in relationshipSet.linkRoleUris:
         modelRoleTypes = self.modelXbrl.roleTypes.get(linkroleUri)
         if modelRoleTypes:
             roledefinition = modelRoleTypes[0].definition
             if not roledefinition:
                 roledefinition = linkroleUri                    
             roleId = modelRoleTypes[0].objectId(self.id)
         else:
             roledefinition = linkroleUri
             roleId = "node{0}".format(self.id)
         self.id += 1
         linkroleUris.append((roledefinition, linkroleUri, roleId))
     linkroleUris.sort()
     # for each URI in definition order
     for linkroleUriTuple in linkroleUris:
         linknode = self.treeView.insert("", "end", linkroleUriTuple[2], text=linkroleUriTuple[0], tags=("ELR",))
         linkRelationshipSet = self.modelXbrl.relationshipSet(self.arcrole, linkroleUriTuple[1], self.linkqname, self.arcqname)
         for rootConcept in linkRelationshipSet.rootConcepts:
             self.viewConcept(rootConcept, rootConcept, "", self.labelrole, linknode, 1, linkRelationshipSet, set())
             self.tag_has[linkroleUriTuple[1]].append(linknode)
Ejemplo n.º 24
0
    def view(self, firstTime=False):
        self.blockSelectEvent = 1
        self.blockViewModelObject = 0
        self.tag_has = defaultdict(list)  # temporary until Tk 8.6
        # relationship set based on linkrole parameter, to determine applicable linkroles
        relationshipSet = self.modelXbrl.relationshipSet(
            self.arcrole, self.linkrole, self.linkqname, self.arcqname)
        if not relationshipSet:
            self.modelXbrl.modelManager.addToLog(
                _("no relationships for {0}").format(self.arcrole))
            return False

        if firstTime:
            # set up treeView widget and tabbed pane
            hdr = self.treeColHdr if self.treeColHdr else _(
                "{0} Relationships").format(
                    XbrlConst.baseSetArcroleLabel(self.arcrole)[1:])
            self.treeView.heading("#0", text=hdr)
            if self.arcrole == XbrlConst.parentChild:  # extra columns
                self.treeView.column("#0", width=300, anchor="w")
                self.treeView["columns"] = ("type", "references")
                self.treeView.column("type",
                                     width=100,
                                     anchor="w",
                                     stretch=False)
                self.treeView.heading("type", text=_("Type"))
                self.treeView.column("references",
                                     width=200,
                                     anchor="w",
                                     stretch=False)
                self.treeView.heading("references", text=_("References"))
            elif self.arcrole == XbrlConst.summationItem:  # extra columns
                self.treeView.column("#0", width=300, anchor="w")
                self.treeView["columns"] = ("weight", "balance")
                self.treeView.column("weight",
                                     width=48,
                                     anchor="w",
                                     stretch=False)
                self.treeView.heading("weight", text=_("Weight"))
                self.treeView.column("balance",
                                     width=70,
                                     anchor="w",
                                     stretch=False)
                self.treeView.heading("balance", text=_("Balance"))
            elif self.arcrole == "XBRL-dimensions":  # add columns for dimensional information
                self.treeView.column("#0", width=300, anchor="w")
                self.treeView["columns"] = ("arcrole", "contextElement",
                                            "closed", "usable")
                self.treeView.column("arcrole",
                                     width=100,
                                     anchor="w",
                                     stretch=False)
                self.treeView.heading("arcrole", text="Arcrole")
                self.treeView.column("contextElement",
                                     width=50,
                                     anchor="center",
                                     stretch=False)
                self.treeView.heading("contextElement", text="Context")
                self.treeView.column("closed",
                                     width=40,
                                     anchor="center",
                                     stretch=False)
                self.treeView.heading("closed", text="Closed")
                self.treeView.column("usable",
                                     width=40,
                                     anchor="center",
                                     stretch=False)
                self.treeView.heading("usable", text="Usable")
            elif self.arcrole == "Table-rendering":  # add columns for dimensional information
                self.treeView.column("#0", width=160, anchor="w")
                self.treeView["columns"] = ("axis", "abstract", "header",
                                            "priItem", "dims")
                self.treeView.column("axis",
                                     width=50,
                                     anchor="center",
                                     stretch=False)
                self.treeView.heading("axis", text="Axis")
                self.treeView.column("abstract",
                                     width=24,
                                     anchor="center",
                                     stretch=False)
                self.treeView.heading("abstract", text="Abs")
                self.treeView.column("header",
                                     width=160,
                                     anchor="w",
                                     stretch=False)
                self.treeView.heading("header", text="Header")
                self.treeView.column("priItem",
                                     width=100,
                                     anchor="w",
                                     stretch=False)
                self.treeView.heading("priItem", text="Primary Item")
                self.treeView.column("dims",
                                     width=150,
                                     anchor="w",
                                     stretch=False)
                self.treeView.heading("dims", text=_("Dimensions"))
        self.id = 1
        for previousNode in self.treeView.get_children(""):
            self.treeView.delete(previousNode)
        # sort URIs by definition
        linkroleUris = []
        for linkroleUri in relationshipSet.linkRoleUris:
            modelRoleTypes = self.modelXbrl.roleTypes.get(linkroleUri)
            if modelRoleTypes:
                roledefinition = (modelRoleTypes[0].definition or linkroleUri)
                roleId = modelRoleTypes[0].objectId(self.id)
            else:
                roledefinition = linkroleUri
                roleId = "node{0}".format(self.id)
            self.id += 1
            linkroleUris.append((roledefinition, linkroleUri, roleId))
        linkroleUris.sort()
        # for each URI in definition order
        for roledefinition, linkroleUri, roleId in linkroleUris:
            linknode = self.treeView.insert("",
                                            "end",
                                            roleId,
                                            text=roledefinition,
                                            tags=("ELR", ))
            linkRelationshipSet = self.modelXbrl.relationshipSet(
                self.arcrole, linkroleUri, self.linkqname, self.arcqname)
            for rootConcept in linkRelationshipSet.rootConcepts:
                self.viewConcept(rootConcept, rootConcept, "", self.labelrole,
                                 linknode, 1, linkRelationshipSet, set())
                self.tag_has[linkroleUri].append(linknode)
Ejemplo n.º 25
0
    def validate(self, modelVersReport):
        self.modelVersReport = modelVersReport
        versReport = modelVersReport.modelDocument
        if not hasattr(versReport, "xmlDocument"): # not parsed
            return
        for DTSname in ("fromDTS", "toDTS"):
            DTSmodelXbrl = getattr(versReport, DTSname)
            if DTSmodelXbrl is None or DTSmodelXbrl.modelDocument is None:
                self.modelVersReport.error(
                    _("{0} is missing or not loaded").format(DTSname),
                    "err", "vere:invalidDTSIdentifier")
            else:
                # validate DTS
                ValidateXbrl.ValidateXbrl(DTSmodelXbrl).validate(DTSmodelXbrl)
                if len(DTSmodelXbrl.errors) > 0:
                    self.modelVersReport.error(
                        _("{0} {1} has errors: {2}").format(DTSname,
                            DTSmodelXbrl.modelDocument.basename, 
                            DTSmodelXbrl.errors), 
                        "err", "vere:invalidDTSIdentifier")
        # validate linkbases
        ValidateXbrl.ValidateXbrl(self.modelVersReport).validate(modelVersReport)

        versReportElt = versReport.xmlRootElement
        # check actions
        for assignmentRef in versReportElt.getElementsByTagNameNS(XbrlConst.ver,"assignmentRef"):
            ref = assignmentRef.getAttribute("ref")
            if ref not in versReport.idObjects or \
               not isinstance(versReport.idObjects[ref], ModelVersObject.ModelAssignment):
                    self.modelVersReport.error(
                        _("AssignmentRef {0} does not reference an assignment").format(ref), 
                        "err", "vere:invalidAssignmentRef")
                    
        # check namespace renames
        for NSrename in versReport.namespaceRenameFrom.values():
            if NSrename.fromURI not in versReport.fromDTS.namespaceDocs:
                self.modelVersReport.error(
                    _("NamespaceRename fromURI {0} does not reference a schema in fromDTS").format(
                    NSrename.fromURI), 
                    "err", "vere:invalidNamespaceMapping")
            if NSrename.toURI not in versReport.toDTS.namespaceDocs:
                self.modelVersReport.error(
                    _("NamespaceRename toURI {0} does not reference a schema in toDTS").format(
                    NSrename.toURI), 
                    "err", "vere:invalidNamespaceMapping")
                
        # check role changes
        for roleChange in versReport.roleChanges.values():
            if roleChange.fromURI not in versReport.fromDTS.roleTypes:
                self.modelVersReport.error(
                    _("RoleChange fromURI {0} does not reference a roleType in fromDTS").format(
                    roleChange.fromURI), 
                    "err", "vere:invalidRoleChange")
            if roleChange.toURI not in versReport.toDTS.roleTypes:
                self.modelVersReport.error(
                    _("RoleChange toURI {0} does not reference a roleType in toDTS").format(
                    roleChange.toURI), 
                    "err", "vere:invalidRoleChange")
                
        # check reportRefs
        # check actions
        for reportRef in versReportElt.getElementsByTagNameNS(XbrlConst.ver,"reportRef"):
            xlinkType = reportRef.getAttributeNS(XbrlConst.xlink, "type")
            if xlinkType != "simple":
                self.modelVersReport.error(
                    _("ReportRef xlink:type {0} must be \"simple\"").format(xlinkType), 
                    "err", "vere:invalidXlinkType")
            # if existing it must be valid
            href = reportRef.getAttributeNS(XbrlConst.xlink, "href")
            # TBD
            
            if not reportRef.hasAttributeNS(XbrlConst.xlink, "arcrole"):
                self.modelVersReport.error(
                    _("ReportRef xlink:arcrole is missing"), 
                    "err", "vere:missingXlinkArcrole")
            else:
                arcrole = reportRef.getAttributeNS(XbrlConst.xlink, "arcrole")
                if arcrole != "http://xbrl.org/arcrole/2010/versioning/related-report":
                    self.modelVersReport.error(
                        _("ReportRef xlink:arcrole {0} is invalid").format(arcrole), 
                        "err", "vere:invalidXlinkArcrole")
            
        if versReport.fromDTS and versReport.toDTS:
            # check concept changes of concept basic
            for conceptChange in versReport.conceptBasicChanges:
                if conceptChange.name != "conceptAdd" and \
                   (conceptChange.fromConcept is None or \
                    conceptChange.fromConcept.qname not in versReport.fromDTS.qnameConcepts):
                    self.modelVersReport.error(
                        _("{0} fromConcept {1} does not reference a concept in fromDTS").format(
                        conceptChange.name, conceptChange.fromConceptQname), 
                        "err", "vercbe:invalidConceptReference")
                if conceptChange.name != "conceptDelete" and \
                   (conceptChange.toConcept is None or \
                    conceptChange.toConcept.qname not in versReport.toDTS.qnameConcepts):
                    self.modelVersReport.error(
                        _("{0} toConcept {1} does not reference a concept in toDTS").format(
                        conceptChange.name, conceptChange.toConceptQname), 
                        "err", "vercbe:invalidConceptReference")
                    
            # check concept changes of concept extended
            for conceptChange in versReport.conceptExtendedChanges:
                fromConcept = conceptChange.fromConcept
                toConcept = conceptChange.toConcept
                fromResource = conceptChange.fromResource
                toResource = conceptChange.toResource
                # fromConcept checks
                if not conceptChange.name.endswith("Add"):
                    if not fromConcept:
                        self.modelVersReport.error(
                            _("{0} {1} fromConcept {2} does not reference a concept in fromDTS").format(
                            conceptChange.actionId, conceptChange.name, conceptChange.fromConceptQname), 
                            "err", "vercbe:invalidConceptReference")
                    # tuple check
                    elif "Child" in conceptChange.name and \
                        not versReport.fromDTS.qnameConcepts[fromConcept.qname] \
                            .isTuple:
                        self.modelVersReport.error(
                            _("{0} {1} fromConcept {2} must be defined as a tuple").format(
                            conceptChange.actionId, conceptChange.name, conceptChange.fromConceptQname), 
                            "err", "vercbe:invalidConceptReference")
                    # resource check
                    elif "Label" in conceptChange.name:
                        if not fromResource:
                            self.modelVersReport.error(
                                _("{0} {1} fromResource {2} does not reference a resource in fromDTS").format(
                                conceptChange.actionId, conceptChange.name, conceptChange.fromResourceValue), 
                                "err", "vercee:invalidContentResourceIdentifier")
                        else:
                            relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.conceptLabel)
                            if relationship:
                                if relationship.qname != XbrlConst.qnLinkLabelArc or \
                                   relationship.parentQname != XbrlConst.qnLinkLabelLink or \
                                   fromResource.qname != XbrlConst.qnLinkLabel:
                                    self.modelVersReport.error(
                                        _("{0} {1} fromResource {2} for {3} in fromDTS does not have expected link, arc, or label elements").format(
                                        conceptChange.actionId, conceptChange.name, conceptChange.fromResourceValue, conceptChange.fromConceptQname), 
                                        "err", "vercee:invalidConceptLabelIdentifier")
                            else:
                                relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.elementLabel)
                                if relationship:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       fromResource.qname != XbrlConst.qnGenLabel:
                                        self.modelVersReport.error(
                                            _("{0} {1} fromResource {2} for {3} in fromDTS does not have expected link, arc, or label elements").format(
                                            conceptChange.actionId, conceptChange.name, conceptChange.fromResourceValue, conceptChange.fromConceptQname), 
                                            "err", "vercee:invalidConceptLabelIdentifier")
                                else:
                                    self.modelVersReport.error(
                                        _("{0} {1} fromResource {2} does not have a label relationship to {3} in fromDTS").format(
                                        conceptChange.actionId, conceptChange.name, conceptChange.fromResourceValue, conceptChange.fromConceptQname), 
                                        "err", "vercee:invalidContentResourceIdentifier")
                    elif "Reference" in conceptChange.name:
                        if not fromResource:
                            self.modelVersReport.error(
                                _("{0} {1} fromResource {2} does not reference a resource in fromDTS").format(
                                conceptChange.actionId, conceptChange.name, conceptChange.fromResourceValue), 
                                "err", "vercee:invalidContentResourceIdentifier")
                        else:
                            relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.conceptReference)
                            if relationship:
                                if relationship.qname != XbrlConst.qnLinkReferenceArc or \
                                   relationship.parentQname != XbrlConst.qnLinkReferenceLink or \
                                   fromResource.qname != XbrlConst.qnLinkReference:
                                    self.modelVersReport.error(
                                        _("{0} {1} fromResource {2} for {3} in fromDTS does not have expected link, arc, or label elements").format(
                                        conceptChange.actionId, conceptChange.name, conceptChange.fromResourceValue, conceptChange.fromConceptQname), 
                                        "err", "vercee:invalidConceptReferenceIdentifier")
                            else:
                                relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.elementReference)
                                if relationship:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       fromResource.qname != XbrlConst.qnGenReference:
                                        self.modelVersReport.error(
                                            _("{0} {1} fromResource {2} for {3} in fromDTS does not have expected link, arc, or label elements").format(
                                            conceptChange.actionId, conceptChange.name, conceptChange.fromResourceValue, conceptChange.fromConceptQname), 
                                            "err", "vercee:invalidConceptReferenceIdentifier")
                                else:
                                    self.modelVersReport.error(
                                        _("{0} {1} fromResource {2} does not have a reference relationship to {3} in fromDTS").format(
                                        conceptChange.actionId, conceptChange.name, conceptChange.fromResourceValue, conceptChange.fromConceptQname), 
                                        "err", "vercee:invalidContentResourceIdentifier")
                             
                # toConcept checks
                if not conceptChange.name.endswith("Delete"):
                    if not toConcept:
                        self.modelVersReport.error(
                            _("{0} {1} toConcept {2} does not reference a concept in toDTS").format(
                            conceptChange.actionId, conceptChange.name, conceptChange.toConceptQname), 
                            "err", "vercbe:invalidConceptReference")
                    # tuple check
                    elif "Child" in conceptChange.name and \
                        not versReport.toDTS.qnameConcepts[toConcept.qname] \
                            .isTuple:
                        self.modelVersReport.error(
                            _("{0} {1} toConcept {2} must be defined as a tuple").format(
                            conceptChange.actionId, conceptChange.name, conceptChange.toConceptQname), 
                            "err", "vercbe:invalidConceptReference")
                    # resource check
                    elif "Label" in conceptChange.name:
                        if not toResource:
                            self.modelVersReport.error(
                                _("{0} {1} toResource {2} does not reference a resource in toDTS").format(
                                conceptChange.actionId, conceptChange.name, conceptChange.toResourceValue), 
                                "err", "vercee:invalidContentResourceIdentifier")
                        else:
                            relationship = toConcept.relationshipToResource(toResource, XbrlConst.conceptLabel)
                            if relationship:
                                if relationship.qname != XbrlConst.qnLinkLabelArc or \
                                   relationship.parentQname != XbrlConst.qnLinkLabelLink or \
                                   toResource.qname != XbrlConst.qnLinkLabel:
                                    self.modelVersReport.error(
                                        _("{0} {1} toResource {2} for {3} in toDTS does not have expected link, arc, or label elements").format(
                                        conceptChange.actionId, conceptChange.name, conceptChange.toResourceValue, conceptChange.toConceptQname), 
                                        "err", "vercee:invalidConceptLabelIdentifier")
                            else:
                                relationship = toConcept.relationshipToResource(toResource, XbrlConst.elementLabel)
                                if relationship:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       toResource.qname != XbrlConst.qnGenLabel:
                                        self.modelVersReport.error(
                                            _("{0} {1} toResource {2} for {3} in toDTS does not have expected link, arc, or label elements").format(
                                            conceptChange.actionId, conceptChange.name, conceptChange.toResourceValue, conceptChange.toConceptQname), 
                                            "err", "vercee:invalidConceptLabelIdentifier")
                                else:
                                    self.modelVersReport.error(
                                        _("{0} {1} toResource {2} does not have a label relationship to {3} in toDTS").format(
                                        conceptChange.actionId, conceptChange.name, conceptChange.toResourceValue, conceptChange.toConceptQname), 
                                        "err", "vercee:invalidContentResourceIdentifier")
                    elif "Reference" in conceptChange.name:
                        if not toResource:
                            self.modelVersReport.error(
                                _("{0} {1} toResource {2} does not reference a resource in toDTS").format(
                                conceptChange.actionId, conceptChange.name, conceptChange.toResourceValue), 
                                "err", "vercee:invalidContentResourceIdentifier")
                        else:
                            relationship = toConcept.relationshipToResource(toResource, XbrlConst.conceptReference)
                            if relationship:
                                if relationship.qname != XbrlConst.qnLinkReferenceArc or \
                                   relationship.parentQname != XbrlConst.qnLinkReferenceLink or \
                                   toResource.qname != XbrlConst.qnLinkReference:
                                    self.modelVersReport.error(
                                        _("{0} {1} toResource {2} for {3} in toDTS does not have expected link, arc, or label elements").format(
                                        conceptChange.actionId, conceptChange.name, conceptChange.toResourceValue, conceptChange.toConceptQname), 
                                        "err", "vercee:invalidConceptReferenceIdentifier")
                            else:
                                relationship = toConcept.relationshipToResource(toResource, XbrlConst.elementReference)
                                if relationship:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       toResource.qname != XbrlConst.qnGenReference:
                                        self.modelVersReport.error(
                                            _("{0} {1} toResource {2} for {3} in toDTS does not have expected link, arc, or label elements").format(
                                            conceptChange.actionId, conceptChange.name, conceptChange.toResourceValue, conceptChange.toConceptQname), 
                                            "err", "vercee:invalidConceptReferenceIdentifier")
                                else:
                                    self.modelVersReport.error(
                                        _("{0} {1} toResource {2} does not have a reference relationship to {3} in toDTS").format(
                                        conceptChange.actionId, conceptChange.name, conceptChange.toResourceValue, conceptChange.toConceptQname), 
                                        "err", "vercee:invalidContentResourceIdentifier")
                        
                # check concept correspondence
                if fromConcept and toConcept:
                    if versReport.toDTSqname(fromConcept.qname) != toConcept.qname and \
                       versReport.equivalentConcepts.get(fromConcept.qname) != toConcept.qname and \
                       toConcept.qname not in versReport.relatedConcepts.get(fromConcept.qname,[]):
                        self.modelVersReport.error(
                            _("{0} {1} fromConcept {2} and toConcept {3} must be equivalent or related").format(
                            conceptChange.actionId, conceptChange.name, conceptChange.fromConceptQname, conceptChange.toConceptQname), 
                            "err", "vercee:invalidConceptCorrespondence")
    
                # custom attribute events
                if conceptChange.name.startswith("conceptAttribute"):
                    try:
                        for attr in conceptAttributeEventAttributes[conceptChange.name]:
                            customAttributeQname = conceptChange.customAttributeQname(attr)
                            if not customAttributeQname or customAttributeQname.namespaceURI is None:
                                self.modelVersReport.error(
                                    _("{0} {1} {2} {3} does not have a namespace").format(
                                    conceptChange.actionId, conceptChange.name, attr, customAttributeQname), 
                                    "err", "vercee:invalidAttributeChange")
                            elif customAttributeQname.namespaceURI in (XbrlConst.xbrli, XbrlConst.xsd):
                                self.modelVersReport.error(
                                    _("{0} {1} {2} {3} has an invalid namespace").format(
                                    conceptChange.actionId, conceptChange.name, attr, customAttributeQname), 
                                    "err", "vercee:illegalCustomAttributeEvent")
                    except KeyError:
                        self.modelVersReport.error(
                            _("{0} {1} event is not recognized").format(conceptChange.actionId, conceptChange.name), 
                            "info", "arelle:eventNotRecognized")
    
            # check relationship set changes
            for relSetChange in versReport.relationshipSetChanges:
                for relationshipSet, name in ((relSetChange.fromRelationshipSet, "fromRelationshipSet"),
                                              (relSetChange.toRelationshipSet, "toRelationshipSet")):
                    if relationshipSet:
                        relationshipSetValid = True
                        if relationshipSet.link and relationshipSet.link not in relationshipSet.dts.qnameConcepts:
                            self.modelVersReport.error(
                                _("{0} link {1} does not reference an element in its DTS").format(
                                relSetChange.name, name, relationshipSet.link), 
                                "err", "verrelse:invalidLinkElementReference")
                            relationshipSetValid = False
                        if relationshipSet.arc and relationshipSet.arc not in relationshipSet.dts.qnameConcepts:
                            self.modelVersReport.error(
                                _("{0} arc {1} does not reference an element in its DTS").format(
                                relSetChange.name, name, relationshipSet.link), 
                                "err", "verrelse:invalidArcElementReference")
                            relationshipSetValid = False
                        if relationshipSet.linkrole and not (XbrlConst.isStandardRole(relationshipSet.linkrole) or
                                                             relationshipSet.linkrole in relationshipSet.dts.roleTypes):
                            self.modelVersReport.error(
                                _("{0} linkrole {1} does not reference an linkrole in its DTS").format(
                                relSetChange.name, name, relationshipSet.linkrole), 
                                "err", "verrelse:invalidLinkrole")
                            relationshipSetValid = False
                        if relationshipSet.arcrole and not (XbrlConst.isStandardArcrole(relationshipSet.arcrole) or
                                                            relationshipSet.arcrole in relationshipSet.dts.arcroleTypes):
                            self.modelVersReport.error(
                                _("{0} arcrole {1} does not reference an arcrole in its DTS").format(
                                relSetChange.name, name, relationshipSet.linkrole), 
                                "err", "verrelse:invalidArcrole")
                            relationshipSetValid = False
                        for relationship in relationshipSet.relationships:
                            # fromConcept checks
                            if not relationship.fromConcept:
                                self.modelVersReport.error(
                                    _("{0} {1} relationship fromConcept {2} does not reference a concept in its DTS").format(
                                    relSetChange.name, name, relationship.fromName), 
                                    "err", "verrelse:invalidConceptReference")
                                relationshipSetValid = False
                            if relationship.toName and not relationship.toConcept:
                                self.modelVersReport.error(
                                    _("{0} {1} relationship toConcept {2} does not reference a concept in its DTS").format(
                                    relSetChange.name, name, relationship.toName), 
                                    "err", "verrelse:invalidConceptReference")
                                relationshipSetValid = False
                            if relationshipSetValid: # test that relations exist
                                if relationship.fromRelationship is None:
                                    if relationship.toName:
                                        self.modelVersReport.error(
                                            _("{0} {1} no relationship found from toConcept {2} to {3} in its DTS").format(
                                            relSetChange.name, name, relationship.fromName, relationship.toName), 
                                            "err", "verrelse:invalidRelationshipReference")
                                    else:
                                        self.modelVersReport.error(
                                            _("{0} {1} no relationship found from toConcept {2} in its DTS").format(
                                            relSetChange.name, name, relationship.fromName), 
                                            "err", "verrelse:invalidRelationshipReference")
                                    

                        
            
            '''
Ejemplo n.º 26
0
Archivo: DTS.py Proyecto: Arelle/Arelle
def checkFilingDTS(val, modelDocument, isEFM, isGFM, visited):
    global targetNamespaceDatePattern, efmFilenamePattern, htmlFileNamePattern, roleTypePattern, arcroleTypePattern, \
            arcroleDefinitionPattern, namePattern, linkroleDefinitionBalanceIncomeSheet
    if targetNamespaceDatePattern is None:
        targetNamespaceDatePattern = re.compile(r"/([12][0-9]{3})-([01][0-9])-([0-3][0-9])|"
                                            r"/([12][0-9]{3})([01][0-9])([0-3][0-9])|")
        efmFilenamePattern = re.compile(r"^[a-z0-9][a-zA-Z0-9_\.\-]*(\.xsd|\.xml|\.htm)$")
        htmlFileNamePattern = re.compile(r"^[a-zA-Z0-9][._a-zA-Z0-9-]*(\.htm)$")
        roleTypePattern = re.compile(r"^.*/role/[^/\s]+$")
        arcroleTypePattern = re.compile(r"^.*/arcrole/[^/\s]+$")
        arcroleDefinitionPattern = re.compile(r"^.*[^\\s]+.*$")  # at least one non-whitespace character
        namePattern = re.compile("[][()*+?\\\\/^{}|@#%^=~`\"';:,<>&$\u00a3\u20ac]") # u20ac=Euro, u00a3=pound sterling 
        linkroleDefinitionBalanceIncomeSheet = re.compile(r"[^-]+-\s+Statement\s+-\s+.*(income|balance|financial\W+position)",
                                                          re.IGNORECASE)
    nonDomainItemNameProblemPattern = re.compile(
        r"({0})|(FirstQuarter|SecondQuarter|ThirdQuarter|FourthQuarter|[1-4]Qtr|Qtr[1-4]|ytd|YTD|HalfYear)(?:$|[A-Z\W])"
        .format(re.sub(r"\W", "", (val.entityRegistrantName or "").title())))
    
        
    visited.append(modelDocument)
    for referencedDocument, modelDocumentReference in modelDocument.referencesDocument.items():
        #6.07.01 no includes
        if modelDocumentReference.referenceType == "include":
            val.modelXbrl.error(("EFM.6.07.01", "GFM.1.03.01"),
                _("Taxonomy schema %(schema)s includes %(include)s, only import is allowed"),
                modelObject=modelDocumentReference.referringModelObject,
                    schema=modelDocument.basename, 
                    include=referencedDocument.basename)
        if referencedDocument not in visited and (referencedDocument.inDTS or referencedDocument.type == ModelDocument.Type.INLINEXBRLDOCUMENTSET): # ignore EdgarRenderer added non-DTS documents
            checkFilingDTS(val, referencedDocument, isEFM, isGFM, visited)
            
    if modelDocument.type == ModelDocument.Type.INLINEXBRLDOCUMENTSET:
        return # nothing to check in inline document set surrogate parent 
            
    if val.disclosureSystem.standardTaxonomiesDict is None:
        pass

    if isEFM: 
        if modelDocument.uri in val.disclosureSystem.standardTaxonomiesDict:
            if modelDocument.targetNamespace:
                # check for duplicates of us-types, dei, and rr taxonomies
                match = standardNamespacesPattern.match(modelDocument.targetNamespace)
                if match is not None:
                    conflictClass = match.group(2) or match.group(5)
                    if (conflictClass == 'us-gaap' and match.group(3) < '2018') or conflictClass == 'srt':
                        val.standardNamespaceConflicts['srt+us-gaap'].add(modelDocument) # ignore non-srt multi-usgaap in Filing.py
                    if conflictClass == 'us-gaap' or conflictClass == 'ifrs-full':
                        val.standardNamespaceConflicts['ifrs+us-gaap'].add(modelDocument)
                    if conflictClass not in ('us-gaap', 'srt'):
                        val.standardNamespaceConflicts[conflictClass].add(modelDocument)
                
        else:
            if len(modelDocument.basename) > 32:
                val.modelXbrl.error("EFM.5.01.01.tooManyCharacters",
                    _("Document file name %(filename)s must not exceed 32 characters."),
                    edgarCode="cp-0501-File-Name-Length",
                    modelObject=modelDocument, filename=modelDocument.basename)
            if modelDocument.type != ModelDocument.Type.INLINEXBRLDOCUMENTSET:
                if modelDocument.type == ModelDocument.Type.INLINEXBRL:
                    _pattern = htmlFileNamePattern
                    _suffix = ".htm"
                else:
                    _pattern = efmFilenamePattern
                    _suffix = ".xsd or .xml"
                if not _pattern.match(modelDocument.basename):
                    val.modelXbrl.error("EFM.5.01.01",
                        _("Document file name %(filename)s must start with a-z or 0-9, contain upper or lower case letters, ., -, _, and end with %(suffix)s."),
                        edgarCode="cp-0501-File-Name",
                        modelObject=modelDocument, filename=modelDocument.basename, suffix=_suffix)
    
    if (modelDocument.type == ModelDocument.Type.SCHEMA and 
        modelDocument.targetNamespace not in val.disclosureSystem.baseTaxonomyNamespaces and
        modelDocument.uri.startswith(val.modelXbrl.uriDir)):
        
        val.hasExtensionSchema = True
        # check schema contents types
        # 6.7.3 check namespace for standard authority
        targetNamespaceAuthority = UrlUtil.authority(modelDocument.targetNamespace) 
        if targetNamespaceAuthority in val.disclosureSystem.standardAuthorities:
            val.modelXbrl.error(("EFM.6.07.03", "GFM.1.03.03"),
                _("The target namespace, %(targetNamespace)s cannot have the same authority (%(targetNamespaceAuthority)s) as a standard "
                  "taxonomy, in %(schema)s.  Please change your target namespace."),
                edgarCode="fs-0703-Extension-Has-Standard-Namespace-Authority",
                modelObject=modelDocument, schema=modelDocument.basename, targetNamespace=modelDocument.targetNamespace, 
                targetNamespaceAuthority=UrlUtil.authority(modelDocument.targetNamespace, includeScheme=False))
            
        # 6.7.4 check namespace format
        if modelDocument.targetNamespace is None or not modelDocument.targetNamespace.startswith("http://"):
            match = None
        else:
            targetNamespaceDate = modelDocument.targetNamespace[len(targetNamespaceAuthority):]
            match = targetNamespaceDatePattern.match(targetNamespaceDate)
        if match is not None:
            try:
                if match.lastindex == 3:
                    date = datetime.date(int(match.group(1)),int(match.group(2)),int(match.group(3)))
                elif match.lastindex == 6:
                    date = datetime.date(int(match.group(4)),int(match.group(5)),int(match.group(6)))
                else:
                    match = None
            except ValueError:
                match = None
        if match is None:
            val.modelXbrl.error(("EFM.6.07.04", "GFM.1.03.04"),
                _("You did not adhere to the requirements for target namespace, for %(targetNamespace)s in %(schema)s.  "
                  "Please recheck your submission and adhere to the target namespace requirements."),
                edgarCode="cp-0704-Taxonomy-Valid-Target-Namespace",
                modelObject=modelDocument, schema=modelDocument.basename, targetNamespace=modelDocument.targetNamespace)
        elif val.fileNameDate and date > val.fileNameDate:
            val.modelXbrl.info(("EFM.6.07.06", "GFM.1.03.06"),
                _("Warning: Taxonomy schema %(schema)s namespace %(targetNamespace)s has date later than document name date %(docNameDate)s"),
                modelObject=modelDocument, schema=modelDocument.basename, targetNamespace=modelDocument.targetNamespace,
                docNameDate=val.fileNameDate)

        if modelDocument.targetNamespace is not None:
            # 6.7.5 check prefix for _
            authority = UrlUtil.authority(modelDocument.targetNamespace)
            if not re.match(r"(http://|https://|ftp://|urn:)\w+",authority):
                val.modelXbrl.error(("EFM.6.07.05", "GFM.1.03.05"),
                    _("Taxonomy schema %(schema)s namespace %(targetNamespace)s must be a valid URI with a valid authority for the namespace."),
                    edgarCode="du-0705-Namespace-Authority",
                    modelObject=modelDocument, schema=modelDocument.basename, targetNamespace=modelDocument.targetNamespace)
            # may be multiple prefixes for namespace
            prefixes = [(prefix if prefix is not None else "")
                        for prefix, NS in modelDocument.xmlRootElement.nsmap.items()
                        if NS == modelDocument.targetNamespace]
            if not prefixes:
                prefix = None
                val.modelXbrl.error(("EFM.6.07.07", "GFM.1.03.07"),
                    _("The schema does not supply a prefix for %(targetNamespace)s without an underscore character, in file %(schema)s. "
                      "Please provide or change a prefix"),
                    edgarCode="du-0707-Recommended-Prefix-Disallowed",
                    modelObject=modelDocument, schema=modelDocument.basename, targetNamespace=modelDocument.targetNamespace)
            else:
                prefix = prefixes[0]
                if len(prefixes) > 1:
                    val.modelXbrl.error(("EFM.6.07.07", "GFM.1.03.07"),
                        _("The schema does not supply a prefix for %(targetNamespace)s without an underscore character, in file %(schema)s. "
                          "Please provide or change a prefix"),
                        edgarCode="du-0707-Recommended-Prefix-Disallowed",
                        modelObject=modelDocument, schema=modelDocument.basename, targetNamespace=modelDocument.targetNamespace, prefix=", ".join(prefixes))
                elif "_" in prefix:
                    val.modelXbrl.error(("EFM.6.07.07", "GFM.1.03.07"),
                        _("The schema does not supply a prefix for %(targetNamespace)s without an underscore character, in file %(schema)s. "
                          "Please provide or change a prefix"),
                        edgarCode="du-0707-Recommended-Prefix-Disallowed",
                        modelObject=modelDocument, schema=modelDocument.basename, targetNamespace=modelDocument.targetNamespace, prefix=prefix)

            for modelConcept in modelDocument.xmlRootElement.iterdescendants(tag="{http://www.w3.org/2001/XMLSchema}element"):
                if isinstance(modelConcept,ModelConcept):
                    # 6.7.16 name not duplicated in standard taxonomies
                    name = modelConcept.get("name")
                    if name is None: 
                        name = ""
                        if modelConcept.get("ref") is not None:
                            continue    # don't validate ref's here
                    for c in val.modelXbrl.nameConcepts.get(name, []):
                        if c.modelDocument != modelDocument:
                            if not c.modelDocument.uri.startswith(val.modelXbrl.uriDir):
                                val.modelXbrl.error(("EFM.6.07.16", "GFM.1.03.18"),
                                    _("Your extension taxonomy contains an element, %(concept)s, which has the same name as an element in the base taxonomy, "
                                      "%(standardConcept)s.  Please ensure that this extension is appropriate and if so, please change the extension concept name."),
                                    edgarCode="cp-0716-Element-Name-Same-As-Base",
                                    modelObject=(modelConcept,c), concept=modelConcept.qname, standardSchema=c.modelDocument.basename, standardConcept=c.qname)

                    # 6.7.17 id properly formed
                    _id = modelConcept.id
                    requiredId = (prefix if prefix is not None else "") + "_" + name
                    if _id != requiredId:
                        val.modelXbrl.error(("EFM.6.07.17", "GFM.1.03.19"),
                            _("You did not adhere to the declarations for concepts by containing an 'id' attribute whose value begins with the recommended "
                              "namespace prefix of the taxonomy, followed by an underscore, followed by an element name, for the concept %(concept)s.  "
                              "Please recheck your submission."),
                            edgarCode="cp-0717-Element-Id",
                            modelObject=modelConcept, concept=modelConcept.qname, id=_id, requiredId=requiredId)
                        
                    # 6.7.18 nillable is true
                    nillable = modelConcept.get("nillable")
                    if nillable != "true" and modelConcept.isItem:
                        val.modelXbrl.error(("EFM.6.07.18", "GFM.1.03.20"),
                            _("Element %(concept)s is declared without a 'true' value for the nillable attribute.  Please set the value to 'true'."),
                            edgarCode="du-0718-Nillable-Not-True",
                            modelObject=modelConcept, schema=modelDocument.basename,
                            concept=name, nillable=nillable)
        
                    # 6.7.19 not tuple
                    if modelConcept.isTuple:
                        val.modelXbrl.error(("EFM.6.07.19", "GFM.1.03.21"),
                            _("You provided an extension concept which is a tuple, %(concept)s.  Please remove tuples and check your submission."),
                            edgarCode="cp-0719-No-Tuple-Element",
                            modelObject=modelConcept, concept=modelConcept.qname)
                        
                    # 6.7.20 no typed domain ref
                    if modelConcept.isTypedDimension:
                        val.modelXbrl.error(("EFM.6.07.20", "GFM.1.03.22"),
                            _("There is an xbrldt:typedDomainRef attribute on %(concept)s (%(typedDomainRef)s). Please remove it."),
                            edgarCode="du-0720-Typed-Domain-Ref-Disallowed",
                            modelObject=modelConcept, concept=modelConcept.qname,
                            typedDomainRef=modelConcept.typedDomainElement.qname if modelConcept.typedDomainElement is not None else modelConcept.typedDomainRef)
                        
                    # 6.7.21 abstract must be duration
                    isDuration = modelConcept.periodType == "duration"
                    if modelConcept.isAbstract and not isDuration:
                        val.modelXbrl.error(("EFM.6.07.21", "GFM.1.03.23"),
                            _("Element %(concept)s is declared as an abstract item with period type 'instant'.  Please change it to 'duration' or "
                              "make the element not abstract."),
                            edgarCode="du-0721-Abstract-Is-Instant",
                            modelObject=modelConcept, schema=modelDocument.basename, concept=modelConcept.qname)
                        
                    # 6.7.22 abstract must be stringItemType
                    ''' removed SEC EFM v.17, Edgar release 10.4, and GFM 2011-04-08
                    if modelConcept.abstract == "true" and modelConcept.typeQname != XbrlConst. qnXbrliStringItemType:
                        val.modelXbrl.error(("EFM.6.07.22", "GFM.1.03.24"),
                            _("Concept %(concept)s  is abstract but type is not xbrli:stringItemType"),
                            modelObject=modelConcept, concept=modelConcept.qname)
					'''
                    substitutionGroupQname = modelConcept.substitutionGroupQname
                    # 6.7.23 Axis must be subs group dimension
                    if name.endswith("Axis") ^ (substitutionGroupQname == XbrlConst.qnXbrldtDimensionItem):
                        val.modelXbrl.error(("EFM.6.07.23", "GFM.1.03.25"),
                            _("The substitution group 'xbrldt:dimensionItem' is only consistent with an element name that ends with 'Axis'.  "
                              "Please change %(conceptLocalName)s or change the substitutionGroup."),
                            edgarCode="du-0723-Axis-Dimension-Name-Mismatch",
                            modelObject=modelConcept, concept=modelConcept.qname, conceptLocalName=modelConcept.qname.localName)

                    # 6.7.24 Table must be subs group hypercube
                    if name.endswith("Table") ^ (substitutionGroupQname == XbrlConst.qnXbrldtHypercubeItem):
                        val.modelXbrl.error(("EFM.6.07.24", "GFM.1.03.26"),
                            _("The substitution group 'xbrldt:hypercubeItem' is only allowed with an element name that ends with 'Table'.  "
                              "Please change %(conceptLocalName)s or change the substitutionGroup."),
                            edgarCode="du-0724-Table-Hypercube-Name-Mismatch",
                            modelObject=modelConcept, schema=modelDocument.basename, concept=modelConcept.qname, conceptLocalName=modelConcept.qname.localName)

                    # 6.7.25 if neither hypercube or dimension, substitution group must be item
                    if substitutionGroupQname not in (None,
                                                        XbrlConst.qnXbrldtDimensionItem, 
                                                        XbrlConst.qnXbrldtHypercubeItem,
                                                        XbrlConst.qnXbrliItem):                           
                        val.modelXbrl.error(("EFM.6.07.25", "GFM.1.03.27"),
                            _("The substitution group attribute value %(substitutionGroup)s of element %(conceptLocalName)s is not allowed.  "
                              "Please change it to one of 'xbrli:item', 'xbrldt:dimensionItem' or 'xbrldt:hypercubeItem'."),
                            edgarCode="du-0725-Substitution-Group-Custom",
                            modelObject=modelConcept, concept=modelConcept.qname, conceptLocalName=modelConcept.qname.localName,
                            substitutionGroup=modelConcept.substitutionGroupQname)
                        
                    # 6.7.26 Table must be subs group hypercube
                    if name.endswith("LineItems") and modelConcept.abstract != "true":
                        val.modelXbrl.error(("EFM.6.07.26", "GFM.1.03.28"),
                            _("The element %(conceptLocalName)s ends with 'LineItems' but is not abstract. Please change %(conceptLocalName)s or "
                              "the value of the 'abstract' attribute."),
                            edgarCode="du-0726-LineItems-Abstract-Name-Mismatch",
                            modelObject=modelConcept, concept=modelConcept.qname, conceptLocalName=modelConcept.qname.localName)

                    # 6.7.27 type domainMember must end with Domain or Member
                    conceptType = modelConcept.type
                    isDomainItemType = conceptType is not None and conceptType.isDomainItemType
                    endsWithDomainOrMember = name.endswith("Domain") or name.endswith("Member")
                    if isDomainItemType != endsWithDomainOrMember:
                        val.modelXbrl.error(("EFM.6.07.27", "GFM.1.03.29"),
                            _("The type 'us-types:domainItemType' is only allowed with an element name that ends with 'Domain' or 'Member'.  "
                              "Please change %(conceptLocalName)s or change the type."),
                            edgarCode="du-0727-Domain-Type-Name-Mismatch",
                            modelObject=modelConcept, concept=modelConcept.qname, conceptLocalName=modelConcept.qname.localName)

                    # 6.7.28 domainItemType must be duration
                    if isDomainItemType and not isDuration:
                        val.modelXbrl.error(("EFM.6.07.28", "GFM.1.03.30"),
                            _("Element %(conceptLocalName)s is declared as a us-types:domainItemType with period type 'instant'.  "
                              "Please change it to 'duration' or change the item type."),
                            edgarCode="du-0728-Domain-Member-Is-Instant",
                            modelObject=modelConcept, concept=modelConcept.qname, conceptLocalName=modelConcept.qname.localName)
                                                
                    #6.7.31 (version 27) fractions
                    if modelConcept.isFraction:
                        val.modelXbrl.error("EFM.6.07.31",
                            _("Element %(concept)s is declared as a fraction item type.  Change or remove the declaration."),
                            edgarCode="du-0731-Fraction-Item-Type",
                            modelObject=modelConcept, concept=modelConcept.qname)
    
                    #6.7.32 (version 27) instant non numeric
                    if modelConcept.isItem and (not modelConcept.isNumeric and not isDuration and not modelConcept.isAbstract and not isDomainItemType):
                        val.modelXbrl.error("EFM.6.07.32",
                            _("Declaration of element %(concept)s in %(schema)s must have xbrli:periodType of 'duration' because its base type is not numeric."),
                            edgarCode="rq-0732-Nonnnumeric-Must-Be-Duration",
                            modelObject=modelConcept, schema=modelDocument.basename, concept=modelConcept.qname)
                        
                    # 6.8.5 semantic check, check LC3 name
                    if name:
                        if not name[0].isupper():
                            val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.05.firstLetter", "GFM.2.03.05.firstLetter"),
                                _("Concept %(concept)s name must start with a capital letter"),
                                modelObject=modelConcept, concept=modelConcept.qname)
                        if namePattern.search(name):
                            val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.05.disallowedCharacter", "GFM.2.03.05.disallowedCharacter"),
                                _("Concept %(concept)s has disallowed name character"),
                                modelObject=modelConcept, concept=modelConcept.qname)
                        if len(name) > 200:
                            val.modelXbrl.log("ERROR-SEMANTIC", "EFM.6.08.05.nameLength",
                                _("Concept %(concept)s name length %(namelength)s exceeds 200 characters"),
                                modelObject=modelConcept, concept=modelConcept.qname, namelength=len(name))
                        
                    if isEFM:
                        label = modelConcept.label(lang="en-US", fallbackToQname=False)
                        if label:
                            # allow Joe's Bar, N.A.  to be JoesBarNA -- remove ', allow A. as not article "a"
                            lc3name = ''.join(re.sub(r"['.-]", "", (w[0] or w[2] or w[3] or w[4])).title()
                                              for w in re.findall(r"((\w+')+\w+)|(A[.-])|([.-]A(?=\W|$))|(\w+)", label) # EFM implies this should allow - and . re.findall(r"[\w\-\.]+", label)
                                              if w[4].lower() not in ("the", "a", "an"))
                            if not(name == lc3name or 
                                   (name and lc3name and lc3name[0].isdigit() and name[1:] == lc3name and (name[0].isalpha() or name[0] == '_'))):
                                val.modelXbrl.log("WARNING-SEMANTIC", "EFM.6.08.05.LC3",
                                    _("Concept %(concept)s should match expected LC3 composition %(lc3name)s"),
                                    modelObject=modelConcept, concept=modelConcept.qname, lc3name=lc3name)
                                
                    if conceptType is not None:
                        # 6.8.6 semantic check
                        if not isDomainItemType and conceptType.qname != XbrlConst.qnXbrliDurationItemType:
                            nameProblems = nonDomainItemNameProblemPattern.findall(name)
                            if any(any(t) for t in nameProblems):  # list of tuples with possibly nonempty strings
                                val.modelXbrl.log("WARNING-SEMANTIC", ("EFM.6.08.06", "GFM.2.03.06"),
                                    _("Concept %(concept)s should not contain company or period information, found: %(matches)s"),
                                    modelObject=modelConcept, concept=modelConcept.qname, 
                                    matches=", ".join(''.join(t) for t in nameProblems))
                        
                        if conceptType.qname == XbrlConst.qnXbrliMonetaryItemType:
                            if not modelConcept.balance:
                                # 6.8.11 may not appear on a income or balance statement
                                if any(linkroleDefinitionBalanceIncomeSheet.match(roleType.definition)
                                       for rel in val.modelXbrl.relationshipSet(XbrlConst.parentChild).toModelObject(modelConcept)
                                       for roleType in val.modelXbrl.roleTypes.get(rel.linkrole,())):
                                    val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.11", "GFM.2.03.11"),
                                        _("Concept %(concept)s must have a balance because it appears in a statement of income or balance sheet"),
                                        modelObject=modelConcept, concept=modelConcept.qname)
                                # 6.11.5 semantic check, must have a documentation label
                                stdLabel = modelConcept.label(lang="en-US", fallbackToQname=False)
                                defLabel = modelConcept.label(preferredLabel=XbrlConst.documentationLabel, lang="en-US", fallbackToQname=False)
                                if not defLabel or ( # want different words than std label
                                    stdLabel and re.findall(r"\w+", stdLabel) == re.findall(r"\w+", defLabel)):
                                    val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.11.05", "GFM.2.04.04"),
                                        _("Concept %(concept)s is monetary without a balance and must have a documentation label that disambiguates its sign"),
                                        modelObject=modelConcept, concept=modelConcept.qname)
                        
                        # 6.8.16 semantic check
                        if conceptType.qname == XbrlConst.qnXbrliDateItemType and modelConcept.periodType != "duration":
                            val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.16", "GFM.2.03.16"),
                                _("Concept %(concept)s of type xbrli:dateItemType must have periodType duration"),
                                modelObject=modelConcept, concept=modelConcept.qname)
                        
                        # 6.8.17 semantic check
                        if conceptType.qname == XbrlConst.qnXbrliStringItemType and modelConcept.periodType != "duration":
                            val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.17", "GFM.2.03.17"),
                                _("Concept %(concept)s of type xbrli:stringItemType must have periodType duration"),
                                modelObject=modelConcept, concept=modelConcept.qname)
                        

        # 6.7.8 check for embedded linkbase
        for e in modelDocument.xmlRootElement.iterdescendants(tag="{http://www.xbrl.org/2003/linkbase}linkbase"):
            if isinstance(e,ModelObject):
                val.modelXbrl.error(("EFM.6.07.08", "GFM.1.03.08"),
                    _("Your filing contained embedded linkbases in %(schema)s.  Please recheck your submission and remove all embedded linkbases."),
                    edgarCode="cp-0708-No-Embedded-Linkbases",
                    modelObject=e, schema=modelDocument.basename)
                break

        requiredUsedOns = {XbrlConst.qnLinkPresentationLink,
                           XbrlConst.qnLinkCalculationLink,
                           XbrlConst.qnLinkDefinitionLink}
        
        standardUsedOns = {XbrlConst.qnLinkLabel, XbrlConst.qnLinkReference, 
                           XbrlConst.qnLinkDefinitionArc, XbrlConst.qnLinkCalculationArc, XbrlConst.qnLinkPresentationArc, 
                           XbrlConst.qnLinkLabelArc, XbrlConst.qnLinkReferenceArc, 
                           # per WH, private footnote arc and footnore resource roles are not allowed
                           XbrlConst.qnLinkFootnoteArc, XbrlConst.qnLinkFootnote,
                           }

        # 6.7.9 role types authority
        for e in modelDocument.xmlRootElement.iterdescendants(tag="{http://www.xbrl.org/2003/linkbase}roleType"):
            if isinstance(e,ModelObject):
                roleURI = e.get("roleURI")
                if targetNamespaceAuthority != UrlUtil.authority(roleURI):
                    val.modelXbrl.error(("EFM.6.07.09", "GFM.1.03.09"),
                        _("Role %(roleType)s does not begin with %(targetNamespace)s's scheme and authority. "
                          "Please change the role URI or target namespace URI."),
                        edgarCode="du-0709-Role-Namespace-Mismatch",
                        modelObject=e, roleType=roleURI, targetNamespaceAuthority=targetNamespaceAuthority, targetNamespace=modelDocument.targetNamespace)
                # 6.7.9 end with .../role/lc3 name
                if not roleTypePattern.match(roleURI):
                    val.modelXbrl.warning(("EFM.6.07.09.roleEnding", "GFM.1.03.09"),
                        "RoleType %(roleType)s should end with /role/{LC3name}",
                        modelObject=e, roleType=roleURI)
                    
                # 6.7.10 only one role type declaration in DTS
                modelRoleTypes = val.modelXbrl.roleTypes.get(roleURI)
                if modelRoleTypes is not None:
                    modelRoleType = modelRoleTypes[0]
                    definition = modelRoleType.definitionNotStripped
                    usedOns = modelRoleType.usedOns
                    if len(modelRoleTypes) == 1:
                        # 6.7.11 used on's for pre, cal, def if any has a used on
                        if not usedOns.isdisjoint(requiredUsedOns) and len(requiredUsedOns - usedOns) > 0:
                            val.modelXbrl.error(("EFM.6.07.11", "GFM.1.03.11"),
                                _("The role %(roleType)s did not provide a usedOn element for all three link types (presentation, "
                                  "calculation and definition), missing %(usedOn)s. Change the declaration to be for all three types of link, and resubmit."),
                                edgarCode="du-0711-Role-Type-Declaration-Incomplete",
                                modelObject=e, roleType=roleURI, usedOn=requiredUsedOns - usedOns)
                            
                        # 6.7.12 definition match pattern
                        if (val.disclosureSystem.roleDefinitionPattern is not None and
                            (definition is None or not val.disclosureSystem.roleDefinitionPattern.match(definition))):
                            val.modelXbrl.error(("EFM.6.07.12", "GFM.1.03.12-14"),
                                _("The definition '%(definition)s' of role %(roleType)s does not match the expected format. "
                                  "Please check that the definition matches {number} - {type} - {text}."),
                                edgarCode="rq-0712-Role-Definition-Mismatch",
                                modelObject=e, roleType=roleURI, definition=(definition or ""))

                    if usedOns & standardUsedOns: # semantics check
                        val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.03", "GFM.2.03.03"),
                            _("RoleType %(roleuri)s is defined using role types already defined by standard roles for: %(qnames)s"),
                            modelObject=e, roleuri=roleURI, qnames=', '.join(str(qn) for qn in usedOns & standardUsedOns))


        # 6.7.13 arcrole types authority
        for e in modelDocument.xmlRootElement.iterdescendants(tag="{http://www.xbrl.org/2003/linkbase}arcroleType"):
            if isinstance(e,ModelObject):
                arcroleURI = e.get("arcroleURI")
                if targetNamespaceAuthority != UrlUtil.authority(arcroleURI):
                    val.modelXbrl.error(("EFM.6.07.13", "GFM.1.03.15"),
                        _("Relationship role %(arcroleType)s does not begin with %(targetNamespace)s's scheme and authority.  "
                          "Please change the relationship role URI or target namespace URI."),
                        edgarCode="du-0713-Arcrole-Namespace-Mismatch",
                        modelObject=e, arcroleType=arcroleURI, targetNamespaceAuthority=targetNamespaceAuthority, targetNamespace=modelDocument.targetNamespace)
                # 6.7.13 end with .../arcrole/lc3 name
                if not arcroleTypePattern.match(arcroleURI):
                    val.modelXbrl.warning(("EFM.6.07.13.arcroleEnding", "GFM.1.03.15"),
                        _("ArcroleType %(arcroleType)s should end with /arcrole/{LC3name}"),
                        modelObject=e, arcroleType=arcroleURI)
                    
                # 6.7.15 definition match pattern
                modelRoleTypes = val.modelXbrl.arcroleTypes[arcroleURI]
                definition = modelRoleTypes[0].definition
                if definition is None or not arcroleDefinitionPattern.match(definition):
                    val.modelXbrl.error(("EFM.6.07.15", "GFM.1.03.17"),
                        _("Relationship role declaration %(arcroleType)s is missing a definition.  Please provide a definition."),
                        edgarCode="du-0715-Arcrole-Definition-Missing",
                        modelObject=e, arcroleType=arcroleURI)
    
                # semantic checks
                usedOns = modelRoleTypes[0].usedOns
                if usedOns & standardUsedOns: # semantics check
                    val.modelXbrl.log("ERROR-SEMANTIC", ("EFM.6.08.03", "GFM.2.03.03"),
                        _("ArcroleType %(arcroleuri)s is defined using role types already defined by standard arcroles for: %(qnames)s"),
                        modelObject=e, arcroleuri=arcroleURI, qnames=', '.join(str(qn) for qn in usedOns & standardUsedOns))



        #6.3.3 filename check
        m = re.match(r"^\w+-([12][0-9]{3}[01][0-9][0-3][0-9]).xsd$", modelDocument.basename)
        if m:
            try: # check date value
                datetime.datetime.strptime(m.group(1),"%Y%m%d").date()
                # date and format are ok, check "should" part of 6.3.3
                if val.fileNameBasePart:
                    expectedFilename = "{0}-{1}.xsd".format(val.fileNameBasePart, val.fileNameDatePart)
                    if modelDocument.basename != expectedFilename:
                        val.modelXbrl.log("WARNING-SEMANTIC", ("EFM.6.03.03.matchInstance", "GFM.1.01.01.matchInstance"),
                            _('Schema file name warning: %(filename)s, should match %(expectedFilename)s'),
                            modelObject=modelDocument, filename=modelDocument.basename, expectedFilename=expectedFilename)
            except ValueError:
                val.modelXbrl.error((val.EFM60303, "GFM.1.01.01"),
                    _('Invalid schema file base name part (date) in "{base}-{yyyymmdd}.xsd": %(filename)s'),
                    modelObject=modelDocument, filename=modelDocument.basename,
                    messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))
        else:
            val.modelXbrl.error((val.EFM60303, "GFM.1.01.01"),
                _('Invalid schema file name, must match "{base}-{yyyymmdd}.xsd": %(filename)s'),
                modelObject=modelDocument, filename=modelDocument.basename,
                messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))

    elif modelDocument.type == ModelDocument.Type.LINKBASE:
        # if it is part of the submission (in same directory) check name
        labelRels = None
        if modelDocument.filepath.startswith(val.modelXbrl.modelDocument.filepathdir):
            #6.3.3 filename check
            extLinkElt = XmlUtil.descendant(modelDocument.xmlRootElement, XbrlConst.link, "*", "{http://www.w3.org/1999/xlink}type", "extended")
            if extLinkElt is None:# no ext link element
                val.modelXbrl.error((val.EFM60303 + ".noLinkElement", "GFM.1.01.01.noLinkElement"),
                    _('Invalid linkbase file name: %(filename)s, has no extended link element, cannot determine link type.'),
                    modelObject=modelDocument, filename=modelDocument.basename,
                    messageCodes=("EFM.6.03.03.noLinkElement", "EFM.6.23.01.noLinkElement",  "GFM.1.01.01.noLinkElement"))
            elif extLinkElt.localName not in extLinkEltFileNameEnding:
                val.modelXbrl.error("EFM.6.03.02",
                    _('Invalid linkbase link element %(linkElement)s in %(filename)s'),
                    modelObject=modelDocument, linkElement=extLinkElt.localName, filename=modelDocument.basename)
            else:
                m = re.match(r"^\w+-([12][0-9]{3}[01][0-9][0-3][0-9])(_[a-z]{3}).xml$", modelDocument.basename)
                expectedSuffix = extLinkEltFileNameEnding[extLinkElt.localName]
                if m and m.group(2) == expectedSuffix:
                    try: # check date value
                        datetime.datetime.strptime(m.group(1),"%Y%m%d").date()
                        # date and format are ok, check "should" part of 6.3.3
                        if val.fileNameBasePart:
                            expectedFilename = "{0}-{1}{2}.xml".format(val.fileNameBasePart, val.fileNameDatePart, expectedSuffix)
                            if modelDocument.basename != expectedFilename:
                                val.modelXbrl.log("WARNING-SEMANTIC", ("EFM.6.03.03.matchInstance", "GFM.1.01.01.matchInstance"),
                                    _('Linkbase name warning: %(filename)s should match %(expectedFilename)s'),
                                    modelObject=modelDocument, filename=modelDocument.basename, expectedFilename=expectedFilename)
                    except ValueError:
                        val.modelXbrl.error((val.EFM60303, "GFM.1.01.01"),
                            _('Invalid linkbase base file name part (date) in "{base}-{yyyymmdd}_{suffix}.xml": %(filename)s'),
                            modelObject=modelDocument, filename=modelDocument.basename,
                            messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))
                else:
                    val.modelXbrl.error((val.EFM60303, "GFM.1.01.01"),
                        _('Invalid linkbase name, must match "{base}-{yyyymmdd}%(expectedSuffix)s.xml": %(filename)s'),
                        modelObject=modelDocument, filename=modelDocument.basename, expectedSuffix=expectedSuffix,
                        messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))
                if extLinkElt.localName == "labelLink":
                    if labelRels is None:
                        labelRels = val.modelXbrl.relationshipSet(XbrlConst.conceptLabel)
                    for labelElt in XmlUtil.children(extLinkElt, XbrlConst.link, "label"):
                        # 6.10.9
                        if XbrlConst.isNumericRole(labelElt.role):
                            for rel in labelRels.toModelObject(labelElt):
                                if rel.fromModelObject is not None and not rel.fromModelObject.isNumeric:
                                    val.modelXbrl.error("EFM.6.10.09",
                                        _("Non-numeric element %(concept)s has a label role for numeric elements: %(role)s. "
                                          "Please change the role attribute."), 
                                        edgarCode="du-1009-Numeric-Label-Role",
                                        modelObject=(labelElt, rel.fromModelObject), concept=rel.fromModelObject.qname, role=labelElt.role)
Ejemplo n.º 27
0
def checkDTSdocument(val, modelDocument, isFilingDocument):
    for hrefElt, _hrefedDoc, hrefId in modelDocument.hrefObjects:
        if hrefId:  #check scheme regardless of whether document loaded
            # check all xpointer schemes
            for scheme, _path in XmlUtil.xpointerSchemes(hrefId):
                if scheme == "element" and val.validateDisclosureSystem:
                    val.modelXbrl.error(
                        ("EFM.6.03.06", "GFM.1.01.03"),
                        _("Href %(elementHref)s may only have shorthand xpointers"
                          ),
                        modelObject=hrefElt,
                        elementHref=hrefElt.get(
                            "{http://www.w3.org/1999/xlink}href"))

    if not isFilingDocument:
        return  # not a filing's extension document

    if modelDocument.type == ModelDocument.Type.SCHEMA:
        if modelDocument.targetNamespace is not None and len(
                modelDocument.targetNamespace) > 85:
            l = len(modelDocument.targetNamespace.encode("utf-8"))
            if l > 255:
                val.modelXbrl.error(
                    "EFM.6.07.30",
                    _("Schema targetNamespace length (%(length)s) is over 255 bytes long in utf-8 %(targetNamespace)s"
                      ),
                    modelObject=modelDocument.xmlRootElement,
                    length=l,
                    targetNamespace=modelDocument.targetNamespace,
                    value=modelDocument.targetNamespace)

    if modelDocument.type in (ModelDocument.Type.SCHEMA,
                              ModelDocument.Type.LINKBASE):
        isSchema = modelDocument.type == ModelDocument.Type.SCHEMA
        if isSchema:
            for elt in modelDocument.xmlRootElement.iter(
                    tag="{http://www.w3.org/2001/XMLSchema}*"):
                if elt.namespaceURI == XbrlConst.xsd:
                    localName = elt.localName
                    if localName in {"element", "complexType", "simpleType"}:
                        name = elt.get("name")
                        if name and len(name) > 64:
                            l = len(name.encode("utf-8"))
                            if l > 200:
                                val.modelXbrl.error(
                                    "EFM.6.07.29",
                                    _("Schema %(element)s has a name length (%(length)s) over 200 bytes long in utf-8, %(name)s."
                                      ),
                                    modelObject=elt,
                                    element=localName,
                                    name=name,
                                    length=l)

    for elt in modelDocument.xmlRootElement.iter():
        if isinstance(elt, ModelObject):
            xlinkType = elt.get("{http://www.w3.org/1999/xlink}type")
            xlinkRole = elt.get("{http://www.w3.org/1999/xlink}role")
            if elt.namespaceURI == XbrlConst.link:
                # check schema roleTypes
                if elt.localName in ("roleType", "arcroleType"):
                    uriAttr = {
                        "roleType": "roleURI",
                        "arcroleType": "arcroleURI"
                    }[elt.localName]
                    roleURI = elt.get(uriAttr)
                    if len(roleURI) > 85:
                        l = len(roleURI.encode("utf-8"))
                        if l > 255:
                            val.modelXbrl.error(
                                "EFM.6.07.30",
                                _("Schema %(element)s %(attribute)s length (%(length)s) is over 255 bytes long in utf-8 %(roleURI)s"
                                  ),
                                modelObject=elt,
                                element=elt.qname,
                                attribute=uriAttr,
                                length=l,
                                roleURI=roleURI,
                                value=roleURI)

                if elt.localName == "arcroleRef":
                    refUri = elt.get("arcroleURI")
                    hrefAttr = elt.get("{http://www.w3.org/1999/xlink}href")
                    hrefUri, hrefId = UrlUtil.splitDecodeFragment(hrefAttr)
                    if hrefUri not in val.disclosureSystem.standardTaxonomiesDict:
                        val.modelXbrl.error(
                            ("EFM.6.09.06", "GFM.1.04.06"),
                            _("Arcrole %(refURI)s arcroleRef %(xlinkHref)s must be a standard taxonomy"
                              ),
                            modelObject=elt,
                            refURI=refUri,
                            xlinkHref=hrefUri)
            if modelDocument.type == ModelDocument.Type.INLINEXBRL and elt.namespaceURI in XbrlConst.ixbrlAll:
                if elt.localName == "footnote":
                    if val.validateGFM:
                        if elt.get("{http://www.w3.org/1999/xlink}arcrole"
                                   ) != XbrlConst.factFootnote:
                            # must be in a nonDisplay div
                            if not any(
                                    inlineDisplayNonePattern.search(
                                        e.get("style") or "")
                                    for e in XmlUtil.ancestors(
                                        elt, XbrlConst.xhtml, "div")):
                                val.modelXbrl.error(
                                    ("EFM.N/A", "GFM:1.10.16"),
                                    _("Inline XBRL footnote %(footnoteID)s must be in non-displayable div due to arcrole %(arcrole)s"
                                      ),
                                    modelObject=elt,
                                    footnoteID=elt.get("footnoteID"),
                                    arcrole=elt.get(
                                        "{http://www.w3.org/1999/xlink}arcrole"
                                    ))

                        if not elt.get(
                                "{http://www.w3.org/XML/1998/namespace}lang"):
                            val.modelXbrl.error(
                                ("EFM.N/A", "GFM:1.10.13"),
                                _("Inline XBRL footnote %(footnoteID)s is missing an xml:lang attribute"
                                  ),
                                modelObject=elt,
                                footnoteID=id)
            if xlinkType == "extended":
                if not xlinkRole or xlinkRole == "":
                    val.modelXbrl.error(("EFM.6.09.04", "GFM.1.04.04"),
                                        "%(element)s is missing an xlink:role",
                                        modelObject=elt,
                                        element=elt.qname)
                if not val.extendedElementName:
                    val.extendedElementName = elt.qname
                elif val.extendedElementName != elt.qname:
                    val.modelXbrl.error(
                        ("EFM.6.09.07", "GFM:1.04.07"),
                        _("Extended element %(element)s must be the same as %(element2)s"
                          ),
                        modelObject=elt,
                        element=elt.qname,
                        element2=val.extendedElementName)
            elif xlinkType == "resource":
                if not xlinkRole:
                    val.modelXbrl.error(
                        ("EFM.6.09.04", "GFM.1.04.04"),
                        _("%(element)s is missing an xlink:role"),
                        modelObject=elt,
                        element=elt.qname)
                elif not XbrlConst.isStandardRole(xlinkRole):
                    modelsRole = val.modelXbrl.roleTypes.get(xlinkRole)
                    if (modelsRole is None or len(modelsRole) == 0
                            or modelsRole[0].modelDocument.targetNamespace
                            not in val.disclosureSystem.standardTaxonomiesDict
                        ):
                        val.modelXbrl.error(
                            ("EFM.6.09.05", "GFM.1.04.05"),
                            _("Resource %(xlinkLabel)s role %(role)s is not a standard taxonomy role"
                              ),
                            modelObject=elt,
                            xlinkLabel=elt.get(
                                "{http://www.w3.org/1999/xlink}label"),
                            role=xlinkRole,
                            element=elt.qname,
                            roleDefinition=val.modelXbrl.roleTypeDefinition(
                                xlinkRole))
            elif xlinkType == "arc":
                if elt.get("priority") is not None:
                    priority = elt.get("priority")
                    try:
                        if int(priority) >= 10:
                            val.modelXbrl.error(
                                ("EFM.6.09.09", "GFM.1.04.08"),
                                _("Arc from %(xlinkFrom)s to %(xlinkTo)s priority %(priority)s must be less than 10"
                                  ),
                                modelObject=elt,
                                arcElement=elt.qname,
                                xlinkFrom=elt.get(
                                    "{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get(
                                    "{http://www.w3.org/1999/xlink}to"),
                                priority=priority)
                    except (ValueError):
                        val.modelXbrl.error(
                            ("EFM.6.09.09", "GFM.1.04.08"),
                            _("Arc from %(xlinkFrom)s to %(xlinkTo)s priority %(priority)s is not an integer"
                              ),
                            modelObject=elt,
                            arcElement=elt.qname,
                            xlinkFrom=elt.get(
                                "{http://www.w3.org/1999/xlink}from"),
                            xlinkTo=elt.get(
                                "{http://www.w3.org/1999/xlink}to"),
                            priority=priority)
                if elt.namespaceURI == XbrlConst.link:
                    if elt.localName == "presentationArc" and not elt.get(
                            "order"):
                        val.modelXbrl.error(
                            ("EFM.6.12.01", "GFM.1.06.01"),
                            _("PresentationArc from %(xlinkFrom)s to %(xlinkTo)s must have an order"
                              ),
                            modelObject=elt,
                            xlinkFrom=elt.get(
                                "{http://www.w3.org/1999/xlink}from"),
                            xlinkTo=elt.get(
                                "{http://www.w3.org/1999/xlink}to"),
                            conceptFrom=arcFromConceptQname(elt),
                            conceptTo=arcToConceptQname(elt))
                    elif elt.localName == "calculationArc":
                        if not elt.get("order"):
                            val.modelXbrl.error(
                                ("EFM.6.14.01", "GFM.1.07.01"),
                                _("CalculationArc from %(xlinkFrom)s to %(xlinkTo)s must have an order"
                                  ),
                                modelObject=elt,
                                xlinkFrom=elt.get(
                                    "{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get(
                                    "{http://www.w3.org/1999/xlink}to"),
                                conceptFrom=arcFromConceptQname(elt),
                                conceptTo=arcToConceptQname(elt))
                        try:
                            weightAttr = elt.get("weight")
                            weight = float(weightAttr)
                            if not weight in (1, -1):
                                val.modelXbrl.error(
                                    ("EFM.6.14.02", "GFM.1.07.02"),
                                    _("CalculationArc from %(xlinkFrom)s to %(xlinkTo)s weight %(weight)s must be 1 or -1"
                                      ),
                                    modelObject=elt,
                                    xlinkFrom=elt.get(
                                        "{http://www.w3.org/1999/xlink}from"),
                                    xlinkTo=elt.get(
                                        "{http://www.w3.org/1999/xlink}to"),
                                    conceptFrom=arcFromConceptQname(elt),
                                    conceptTo=arcToConceptQname(elt),
                                    weight=weightAttr)
                        except ValueError:
                            val.modelXbrl.error(
                                ("EFM.6.14.02", "GFM.1.07.02"),
                                _("CalculationArc from %(xlinkFrom)s to %(xlinkTo)s must have an weight (value error in \"%(weight)s\")"
                                  ),
                                modelObject=elt,
                                xlinkFrom=elt.get(
                                    "{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get(
                                    "{http://www.w3.org/1999/xlink}to"),
                                conceptFrom=arcFromConceptQname(elt),
                                conceptTo=arcToConceptQname(elt),
                                weight=weightAttr)
                    elif elt.localName == "definitionArc":
                        if not elt.get("order"):
                            val.modelXbrl.error(
                                ("EFM.6.16.01", "GFM.1.08.01"),
                                _("DefinitionArc from %(xlinkFrom)s to %(xlinkTo)s must have an order"
                                  ),
                                modelObject=elt,
                                xlinkFrom=elt.get(
                                    "{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get(
                                    "{http://www.w3.org/1999/xlink}to"),
                                conceptFrom=arcFromConceptQname(elt),
                                conceptTo=arcToConceptQname(elt))
Ejemplo n.º 28
0
def presumptionOfTotal(val, rel, siblingRels, iSibling, isStatementSheet, nestedInTotal, checkLabelRoleOnly):
    """
    A numeric concept target of a parent-child relationship is presumed total if:
    
    (i) its preferredLabel role is a total role (pre XbrlConst static function of 
    current such total roles) or
    
    (ii) if not in a nested total (abstract child relationship to a known total's 
    contributing siblings):
    
    the parent is not SupplementalCashFlowInformationAbstract and the preceding 
    sibling relationship is monetary and it's on a statement sheet and it's the 
    last of more than one monetary item
    
    (a) Last monetary parented by an abstract or non-monetary and not in a nested 
    (breakdown) total, or 
    (b) effective label (en-US of preferred role) has "Total" in its wording.
    (c) (commented out for now due to false positives: Concept name has "Total" 
    in its name)
    (d) last monetary (may be sub level) whose immediate sibling is a calc LB child
    """
    concept = rel.toModelObject
    if isinstance(concept, ModelConcept) and concept.isNumeric:
        preferredLabel = rel.preferredLabel
        if XbrlConst.isTotalRole(preferredLabel):
            return _("preferredLabel {0}").format(os.path.basename(preferredLabel))
        if concept.isMonetary and not checkLabelRoleOnly: 
            effectiveLabel = concept.label(lang="en-US", fallbackToQname=False, preferredLabel=preferredLabel)
            ''' word total in label/name does not seem to be a good indicator, 
                e.g., Google Total in label for ShareBasedCompensationArrangementByShareBasedPaymentAwardGrantDateFairValueOfOptionsVested followed by 
                label with Aggregate but name has Total
                ... so only perform this test on last monetary in a Note 
            if 'Total' in effectiveLabel: # also check for Net ???
                return _("word 'Total' in effective label {0}").format(effectiveLabel)
            if 'Total' in concept.name: # also check for Net ???
                return _("word 'Total' in concept name {0}").format(concept.name)
            '''
            parent = rel.fromModelObject
            if (len(siblingRels) > 1 and
                iSibling == len(siblingRels) - 1 and 
                parent is not None and
                parent.name not in {
                    "SupplementalCashFlowInformationAbstract"
                }):
                preceedingSibling = siblingRels[iSibling - 1].toModelObject
                if preceedingSibling is not None and preceedingSibling.isMonetary:
                    # last fact, may be total
                    if isStatementSheet:
                        # check if facts add up??
                        if (parent.isAbstract or not parent.isMonetary) and not nestedInTotal:
                            return _("last monetary item in statement sheet monetary line items parented by nonMonetary concept")
                        elif effectiveLabel and 'Total' in effectiveLabel: 
                            return _("last monetary item in statement sheet monetary line items with word 'Total' in effective label {0}").format(effectiveLabel)
                        elif 'Total' in concept.name:
                            return _("last monetary item in statement sheet monetary line items with word 'Total' in concept name {0}").format(concept.name)
                        elif val.summationItemRelsSetAllELRs.isRelated(concept, "child", preceedingSibling):
                            return _("last monetary item in statement sheet monetary line items is calc sum of previous line item")
                    ''' for now unreliable to use total words for notes
                    else:
                        if 'Total' in effectiveLabel: # also check for Net ???
                            return _("last monetary item in note with word 'Total' in effective label {0}").format(effectiveLabel)
                        if 'Total' in concept.name: # also check for Net ???
                            return _("last monetary item in note with word 'Total' in concept name {0}").format(concept.name)
                    '''
    return None
Ejemplo n.º 29
0
def labelroles(modelXbrl, includeConceptName=False):
    # returns sorted list of tuples of arcrole basename and uri
    return sorted(
        set((XbrlConst.labelroleLabel(r), r) for r in (modelXbrl.labelroles | (
            {XbrlConst.conceptNameLabelRole} if includeConceptName else set()))
            if r is not None))
Ejemplo n.º 30
0
 def isNumeric(self):
     try:
         return self._isNumeric
     except AttributeError:
         self._isNumeric = XbrlConst.isNumericXsdType(self.baseXsdType)
         return self._isNumeric
Ejemplo n.º 31
0
    def validate(self, modelVersReport):
        self.modelVersReport = modelVersReport
        versReport = modelVersReport.modelDocument
        if not hasattr(versReport, "xmlDocument"): # not parsed
            return
        for DTSname in ("fromDTS", "toDTS"):
            DTSmodelXbrl = getattr(versReport, DTSname)
            if DTSmodelXbrl is None or DTSmodelXbrl.modelDocument is None:
                self.modelVersReport.error("vere:invalidDTSIdentifier",
                    _("%(dts)s is missing or not loaded"),
                    modelObject=self, dts=DTSname)
            else:
                # validate DTS
                ValidateXbrl.ValidateXbrl(DTSmodelXbrl).validate(DTSmodelXbrl)
                if len(DTSmodelXbrl.errors) > 0:
                    self.modelVersReport.error("vere:invalidDTSIdentifier",
                        _("%(dts) has errors: %(error)s"),
                        modelObject=DTSmodelXbrl.modelDocument, dts=DTSname, error=DTSmodelXbrl.errors)
        # validate linkbases
        ValidateXbrl.ValidateXbrl(self.modelVersReport).validate(modelVersReport)

        versReportElt = versReport.xmlRootElement
        # check actions
        for assignmentRef in versReportElt.iterdescendants(tag="{http://xbrl.org/2010/versioning-base}assignmentRef"):
            ref = assignmentRef.get("ref")
            if ref not in versReport.idObjects or \
               not isinstance(versReport.idObjects[ref], ModelVersObject.ModelAssignment):
                    self.modelVersReport.error("vere:invalidAssignmentRef",
                        _("AssignmentRef %(assignmentRef)s does not reference an assignment"),
                        modelObject=assignmentRef, assignmentRef=ref)
                    
        # check namespace renames
        for NSrename in versReport.namespaceRenameFrom.values():
            if NSrename.fromURI not in versReport.fromDTS.namespaceDocs:
                self.modelVersReport.error("vere:invalidNamespaceMapping",
                    _("NamespaceRename fromURI %(uri)s does not reference a schema in fromDTS"),
                    modelObject=self, uri=NSrename.fromURI)
            if NSrename.toURI not in versReport.toDTS.namespaceDocs:
                self.modelVersReport.error("vere:invalidNamespaceMapping",
                    _("NamespaceRename toURI %(uri)s does not reference a schema in toDTS"),
                    modelObject=self, uri=NSrename.toURI)
                
        # check role changes
        for roleChange in versReport.roleChanges.values():
            if roleChange.fromURI not in versReport.fromDTS.roleTypes:
                self.modelVersReport.error("vere:invalidRoleChange",
                    _("RoleChange fromURI %(uri)s does not reference a roleType in fromDTS"),
                    modelObject=self, uri=roleChange.fromURI)
            if roleChange.toURI not in versReport.toDTS.roleTypes:
                self.modelVersReport.error("vere:invalidRoleChange",
                    _("RoleChange toURI %(uri)s does not reference a roleType in toDTS"),
                    modelObject=self, uri=roleChange.toURI)
                
        # check reportRefs
        # check actions
        for reportRef in versReportElt.iterdescendants(tag="{http://xbrl.org/2010/versioning-base}reportRef"):
            # if existing it must be valid
            href = reportRef.get("{http://www.w3.org/1999/xlink}href")
            # TBD
            
        if versReport.fromDTS and versReport.toDTS:
            # check concept changes of concept basic
            for conceptChange in versReport.conceptUseChanges:
                fromConceptQn = conceptChange.fromConceptQname
                toConceptQn = conceptChange.toConceptQname
                if (conceptChange.name != "conceptAdd" and 
                    (fromConceptQn is None or fromConceptQn not in versReport.fromDTS.qnameConcepts)):
                    self.modelVersReport.error("vercue:invalidConceptReference",
                        _("%(event)s fromConcept %(concept)s does not reference a concept in fromDTS"),
                        modelObject=conceptChange, event=conceptChange.name, concept=conceptChange.fromConceptQname) 
                if (conceptChange.name != "conceptDelete" and
                    (toConceptQn is None or toConceptQn not in versReport.toDTS.qnameConcepts)):
                    self.modelVersReport.error("vercue:invalidConceptReference",
                        _("%(event)s toConcept %(concept)s does not reference a concept in toDTS"),
                        modelObject=conceptChange, event=conceptChange.name, concept=conceptChange.toConceptQname) 
                if (conceptChange.name == "conceptAdd" and toConceptQn is not None and
                    conceptChange.isPhysical ^
                    (qname(versReport.namespaceRenameTo.get(toConceptQn.namespaceURI, toConceptQn.namespaceURI),
                           toConceptQn.localName) not in versReport.fromDTS.qnameConcepts)):
                    self.modelVersReport.error("vercue:inconsistentPhysicalAttribute",
                        _("%(event)s toConcept %(concept)s physical attribute conflicts with presence in fromDTS"),
                        modelObject=conceptChange, event=conceptChange.name, concept=conceptChange.toConceptQname) 
                if (conceptChange.name == "conceptDelete" and toConceptQn is not None and
                    conceptChange.isPhysical ^
                    (qname(versReport.namespaceRenameFrom.get(fromConceptQn.namespaceURI, fromConceptQn.namespaceURI),
                           fromConceptQn.localName) in versReport.toDTS.qnameConcepts)):
                    self.modelVersReport.error("vercue:inconsistentPhysicalAttribute",
                        _("%(event)s toConcept %(concept)s physical attribute conflicts with presence in toDTS"),
                        modelObject=conceptChange, event=conceptChange.name, concept=conceptChange.toConceptQname) 
                    
            # check concept changes of concept extended
            equivalentAttributes = {}
            for conceptChange in versReport.conceptDetailsChanges:
                fromConcept = conceptChange.fromConcept
                toConcept = conceptChange.toConcept
                fromResource = conceptChange.fromResource
                toResource = conceptChange.toResource
                # fromConcept checks
                if not conceptChange.name.endswith("Add"):
                    if not fromConcept is not None:
                        self.modelVersReport.error("vercue:invalidConceptReference",
                            _("%(action)s %(event)s fromConcept %(concept)s does not reference a concept in fromDTS"),
                            modelObject=conceptChange, action=conceptChange.actionId,
                            event=conceptChange.name, concept=conceptChange.fromConceptQname) 
                    # tuple check
                    elif _("Child") in conceptChange.name and \
                        not versReport.fromDTS.qnameConcepts[fromConcept.qname] \
                            .isTuple:
                        self.modelVersReport.error("vercue:invalidConceptReference",
                            _("%(action)s %(event)s fromConcept %(concept)s must be defined as a tuple"),
                            modelObject=conceptChange, action=conceptChange.actionId,
                            event=conceptChange.name, concept=conceptChange.fromConceptQname) 
                    # resource check
                    elif "Label" in conceptChange.name:
                        if fromResource is None:
                            self.modelVersReport.error("vercde:invalidResourceIdentifier",
                                _("%(action)s %(event)s fromResource %(resource)s does not reference a resource in fromDTS"),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, resource=conceptChange.fromResourceValue) 
                        else:
                            relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.conceptLabel)
                            if relationship is not None:
                                if (relationship.qname != XbrlConst.qnLinkLabelArc or 
                                    relationship.parentQname != XbrlConst.qnLinkLabelLink or 
                                    fromResource.qname != XbrlConst.qnLinkLabel):
                                    self.modelVersReport.error("vercde:invalidConceptLabelIdentifier",
                                        _("%(action)s %(event)s fromResource %(resource)s for %(concept)s in fromDTS does not have expected link, arc, or label elements"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.fromResourceValue, concept=conceptChange.fromConceptQname)
                            else:
                                relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.elementLabel)
                                if relationship is not None:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       fromResource.qname != XbrlConst.qnGenLabel:
                                        self.modelVersReport.error("vercde:invalidConceptLabelIdentifier",
                                            _("%(action)s %(event)s fromResource %(resource)s for %(concept)s in fromDTS does not have expected link, arc, or label elements"),
                                            modelObject=conceptChange, action=conceptChange.actionId,
                                            event=conceptChange.name, resource=conceptChange.fromResourceValue, concept=conceptChange.fromConceptQname)
                                else:
                                    self.modelVersReport.error("vercde:invalidResourceIdentifier",
                                        _("%(action)s %(event)s fromResource %(resource)s does not have a label relationship to {3} in fromDTS"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.fromResourceValue)
                    elif "Reference" in conceptChange.name:
                        if fromResource is None:
                            self.modelVersReport.error("vercde:invalidResourceIdentifier",
                                _("%(action)s %(event)s fromResource %(resource)s does not reference a resource in fromDTS"),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, resource=conceptChange.fromResourceValue)
                        else:
                            relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.conceptReference)
                            if relationship is not None:
                                if relationship.qname != XbrlConst.qnLinkReferenceArc or \
                                   relationship.parentQname != XbrlConst.qnLinkReferenceLink or \
                                   fromResource.qname != XbrlConst.qnLinkReference:
                                    self.modelVersReport.error("vercde:invalidConceptReferenceIdentifier",
                                        _("%(action)s %(event)s fromResource %(resource)s for %(concept)s in fromDTS does not have expected link, arc, or label elements"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.fromResourceValue, concept=conceptChange.fromConceptQname)
                            else:
                                relationship = fromConcept.relationshipToResource(fromResource, XbrlConst.elementReference)
                                if relationship is not None:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       fromResource.qname != XbrlConst.qnGenReference:
                                        self.modelVersReport.error("vercde:invalidConceptReferenceIdentifier",
                                            _("%(action)s %(event)s fromResource %(resource)s for %(concept)s  in fromDTS does not have expected link, arc, or label elements"),
                                            modelObject=conceptChange, action=conceptChange.actionId,
                                            event=conceptChange.name, resource=conceptChange.fromResourceValue, concept=conceptChange.fromConceptQname)
                                else:
                                    self.modelVersReport.error("vercde:invalidResourceIdentifier",
                                        _("%(action)s %(event)s fromResource %(resource)s does not have a reference relationship to %(concept)s in fromDTS"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.fromResourceValue, concept=conceptChange.fromConceptQname)
                             
                # toConcept checks
                if not conceptChange.name.endswith("Delete"):
                    if not toConcept is not None:
                        self.modelVersReport.error("vercue:invalidConceptReference",
                            _("%(action)s %(event)s toConcept %(concept)s does not reference a concept in toDTS"),
                            modelObject=conceptChange, action=conceptChange.actionId,
                            event=conceptChange.name, concept=conceptChange.toConceptQname)
                    # tuple check
                    elif "Child" in conceptChange.name and \
                        not versReport.toDTS.qnameConcepts[toConcept.qname] \
                            .isTuple:
                        self.modelVersReport.error("vercue:invalidConceptReference",
                            _("%(action)s %(event)s toConcept %(concept)s must be defined as a tuple"),
                            modelObject=conceptChange, action=conceptChange.actionId,
                            event=conceptChange.name, concept=conceptChange.toConceptQname)
                    # resource check
                    elif "Label" in conceptChange.name:
                        if toResource is None:
                            self.modelVersReport.error("vercde:invalidResourceIdentifier",
                                _("%(action)s %(event)s toResource %(resource)s for %(concept)s does not reference a resource in toDTS"),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                        elif toResource.qname not in (XbrlConst.qnLinkLabel, XbrlConst.qnGenLabel):
                            self.modelVersReport.error("vercde:invalidConceptLabelIdentifier",
                                _("%(action)s %(event)s toResource %(resource)s is not a label in toDTS"),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                        else:
                            relationship = toConcept.relationshipToResource(toResource, XbrlConst.conceptLabel)
                            if relationship is not None:
                                if relationship.qname != XbrlConst.qnLinkLabelArc or \
                                   relationship.parentQname != XbrlConst.qnLinkLabelLink or \
                                   toResource.qname != XbrlConst.qnLinkLabel:
                                    self.modelVersReport.error("vercde:invalidConceptLabelIdentifier",
                                        _("%(action)s %(event)s toResource %(resource)s for %(concept)s in toDTS does not have expected link, arc, or label elements"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                            else:
                                relationship = toConcept.relationshipToResource(toResource, XbrlConst.elementLabel)
                                if relationship is not None:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       toResource.qname != XbrlConst.qnGenLabel:
                                        self.modelVersReport.error("vercde:invalidConceptLabelIdentifier",
                                            _("%(action)s %(event)s toResource %(resource)s for %(concept)s in toDTS does not have expected link, arc, or label elements"),
                                            modelObject=conceptChange, action=conceptChange.actionId,
                                            event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                                else:
                                    self.modelVersReport.error("vercde:invalidConceptResourceIdentifier",
                                        _("%(action)s %(event)s toResource %(resource)s does not have a label relationship to %(concept)s in toDTS"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                    elif "Reference" in conceptChange.name:
                        if toResource is None:
                            self.modelVersReport.error("vercde:invalidResourceIdentifier",
                                _("%(action)s %(event)s toResource %(resource)s does not reference a resource in toDTS"),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, resource=conceptChange.toResourceValue)
                        elif toResource.qname not in (XbrlConst.qnLinkReference, XbrlConst.qnGenReference):
                            self.modelVersReport.error("vercde:invalidConceptReferenceIdentifier",
                                _("%(action)s %(event)s toResource %(resource)s is not a reference in toDTS"),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                        else:
                            relationship = toConcept.relationshipToResource(toResource, XbrlConst.conceptReference)
                            if relationship is not None:
                                if relationship.qname != XbrlConst.qnLinkReferenceArc or \
                                   relationship.parentQname != XbrlConst.qnLinkReferenceLink or \
                                   toResource.qname != XbrlConst.qnLinkReference:
                                    self.modelVersReport.error("vercde:invalidConceptReferenceIdentifier",
                                        _("%(action)s %(event)s toResource %(resource)s for %(concept)s in toDTS does not have expected link, arc, or label elements"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                            else:
                                relationship = toConcept.relationshipToResource(toResource, XbrlConst.elementReference)
                                if relationship is not None:
                                    if relationship.qname != XbrlConst.qnGenArc or \
                                       toResource.qname != XbrlConst.qnGenReference:
                                        self.modelVersReport.error("vercde:invalidConceptReferenceIdentifier",
                                            _("%(action)s %(event)s toResource %(resource)s for %(concept)s in toDTS does not have expected link, arc, or label elements"),
                                            modelObject=conceptChange, action=conceptChange.actionId,
                                            event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                                else:
                                    self.modelVersReport.error("vercde:invalidConceptResourceIdentifier",
                                        _("%(action)s %(event)s toResource %(resource)s does not have a reference relationship to %(concept)s in toDTS"),
                                        modelObject=conceptChange, action=conceptChange.actionId,
                                        event=conceptChange.name, resource=conceptChange.toResourceValue, concept=conceptChange.toConceptQname)
                        
                # check concept correspondence
                if fromConcept is not None and toConcept is not None:
                    if (versReport.toDTSqname(fromConcept.qname) != toConcept.qname and 
                        versReport.equivalentConcepts.get(fromConcept.qname) != toConcept.qname and 
                        toConcept.qname not in versReport.relatedConcepts.get(fromConcept.qname,[])):
                        self.modelVersReport.error("vercde:invalidConceptCorrespondence",
                            _("%(action)s %(event)s fromConcept %(conceptFrom)s and toConcept %(conceptTo)s must be equivalent or related"),
                            modelObject=conceptChange, action=conceptChange.actionId,
                            event=conceptChange.name, conceptFrom=conceptChange.fromConceptQname, conceptTo=conceptChange.toConceptQname)
    
                # custom attribute events
                if conceptChange.name.startswith("conceptAttribute") or conceptChange.name == "attributeDefinitionChange":
                    try:
                        for attr in conceptAttributeEventAttributes[conceptChange.name]:
                            customAttributeQname = conceptChange.customAttributeQname(attr)
                            if not customAttributeQname:
                                self.modelVersReport.info("arelle:invalidAttributeChange",
                                    _("%(action)s %(event)s %(attr)s $(attrName)s does not have a name"),
                                    modelObject=conceptChange, action=conceptChange.actionId,
                                    attr=attr, attrName=customAttributeQname)
                            elif customAttributeQname.namespaceURI in (None, XbrlConst.xbrli, XbrlConst.xsd):
                                self.modelVersReport.error("vercde:illegalCustomAttributeEvent",
                                    _("%(action)s %(event)s %(attr)s $(attrName)s has an invalid namespace"),
                                    modelObject=conceptChange, action=conceptChange.actionId, event=conceptChange.name,
                                    attr=attr, attrName=customAttributeQname)
                    except KeyError:
                        self.modelVersReport.info("arelle:eventNotRecognized",
                            _("%(action)s %(event)s event is not recognized"),
                            modelObject=conceptChange, action=conceptChange.actionId, event=conceptChange.name)

                if conceptChange.name == "attributeDefinitionChange":
                    fromAttr = conceptChange.customAttributeQname("fromCustomAttribute")
                    toAttr = conceptChange.customAttributeQname("toCustomAttribute")
                    equivalentAttributes[fromAttr] = toAttr
                    equivalentAttributes[toAttr] = fromAttr
                    
                # check item concept identifiers
                if conceptChange.name in ("conceptPeriodTypeChange", "conceptPeriodTypeChange"):
                    for concept in (fromConcept, toConcept):
                        if concept is not None and not concept.isItem:
                            self.modelVersReport.error("vercde:invalidItemConceptIdentifier",
                                _("%(action)s %(event)s concept %(concept)s does not reference an item concept."),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, concept=concept.qname) 
                        
                # check tuple concept identifiers
                if conceptChange.name in ("tupleContentModelChange", ):
                    for concept in (fromConcept, toConcept):
                        if concept is not None and not concept.isItem:
                            self.modelVersReport.error("vercde:invalidTupleConceptIdentifier",
                                _("%(action)s %(event)s concept %(concept)s does not reference a tuple concept."),
                                modelObject=conceptChange, action=conceptChange.actionId,
                                event=conceptChange.name, concept=concept.qname) 
                            
                if conceptChange.name in schemaAttributeEventAttributes:
                    attr = schemaAttributeEventAttributes[conceptChange.name]
                    if (fromConcept is not None and not fromConcept.get(attr) and 
                        toConcept is not None and not toConcept.get(attr)):
                            self.modelVersReport.error("vercde:illegalSchemaAttributeChangeEvent",
                                _("%(action)s %(event)s neither concepts have a %(attribute)s attribute: %(fromConcept)s, %(toConcept)s."),
                                modelObject=conceptChange, action=conceptChange.actionId, attribute=attr,
                                event=conceptChange.name, fromConcept=fromConcept.qname, toConcept=toConcept.qname) 

            # check concept changes for equivalent attributes
            for conceptChange in versReport.conceptDetailsChanges:
                if conceptChange.name == "conceptAttributeChange":
                    fromAttr = conceptChange.customAttributeQname("fromCustomAttribute")
                    toAttr = conceptChange.customAttributeQname("toCustomAttribute")
                    if (equivalentAttributes.get(fromAttr) != toAttr and 
                        (fromAttr.localName != toAttr.localName or
                         (fromAttr.namespaceURI != toAttr.namespaceURI and
                          versReport.namespaceRenameFrom.get(fromAttr.namespaceURI, fromAttr.namespaceURI) != toAttr.namespaceURI))):
                        self.modelVersReport.error("vercde:invalidAttributeCorrespondence",
                            _("%(action)s %(event)s has non-equivalent attributes %(fromQname)s and %(toQname)s"),
                            modelObject=conceptChange, action=conceptChange.actionId, event=conceptChange.name,
                            fromQname=fromAttr, toQname=toAttr)
            del equivalentAttributes # dereference
    
            # check relationship set changes
            for relSetChange in versReport.relationshipSetChanges:
                for relationshipSet, name in ((relSetChange.fromRelationshipSet, "fromRelationshipSet"),
                                              (relSetChange.toRelationshipSet, "toRelationshipSet")):
                    if relationshipSet is not None:
                        dts = relationshipSet.dts
                        relationshipSetValid = True
                        if relationshipSet.link:
                            if (relationshipSet.link not in dts.qnameConcepts or
                                (dts.qnameConcepts[relationshipSet.link].type is not None and
                                 not dts.qnameConcepts[relationshipSet.link].type.isDerivedFrom(XbrlConst.qnXlExtendedType))):
                                self.modelVersReport.error("verrelse:invalidLinkElementReferenceEvent",
                                    _("%(event)s %(relSet)s link %(link)s does not reference an element in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    link=relationshipSet.link)
                                relationshipSetValid = False
                        if relationshipSet.arc:
                            if (relationshipSet.arc not in dts.qnameConcepts or
                                (dts.qnameConcepts[relationshipSet.arc].type is not None and
                                 not dts.qnameConcepts[relationshipSet.arc].type.isDerivedFrom(XbrlConst.qnXlArcType))):
                                self.modelVersReport.error("verrelse:invalidArcElementReferenceEvent",
                                    _("%(event)s %(relSet)s arc %(arc) does not reference an element in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    arc=relationshipSet.arc)
                                relationshipSetValid = False
                        if relationshipSet.linkrole:
                            if not (XbrlConst.isStandardRole(relationshipSet.linkrole) or
                                    relationshipSet.linkrole in relationshipSet.dts.roleTypes):
                                self.modelVersReport.error("verrelse:invalidLinkrole",
                                    _("%(event)s %(relSet)s linkrole %(linkrole)s does not reference an linkrole in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    linkrole=relationshipSet.linkrole)
                                relationshipSetValid = False
                            elif not any(linkrole == relationshipSet.linkrole
                                         for arcrole, linkrole, linkqname, arcqname in dts.baseSets.keys()):
                                self.modelVersReport.error("verrelse:invalidLinkrole",
                                    _("%(event)s %(relSet)s linkrole %(linkrole)s is not used in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    linkrole=relationshipSet.linkrole)
                                relationshipSetValid = False
                        if relationshipSet.arcrole:
                            if not (XbrlConst.isStandardArcrole(relationshipSet.arcrole) or
                                    relationshipSet.arcrole in relationshipSet.dts.arcroleTypes):
                                self.modelVersReport.error("verrelse:invalidArcrole",
                                    _("%(event)s %(relSet)s arcrole %(arcrole)s does not reference an arcrole in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    arcrole=relationshipSet.arcrole)
                                relationshipSetValid = False
                            elif not any(arcrole == relationshipSet.arcrole
                                         for arcrole, linkrole, linkqname, arcqname in dts.baseSets.keys()):
                                self.modelVersReport.error("verrelse:invalidArcrole",
                                    _("%(event)s %(relSet)s arcrole %(arcrole)s is not used in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    arcrole=relationshipSet.arcrole)
                                relationshipSetValid = False
                        for relationship in relationshipSet.relationships:
                            # fromConcept checks
                            if relationship.fromConcept is None:
                                self.modelVersReport.error("vercue:invalidConceptReference",
                                    _("%(event)s %(relSet)s relationship fromConcept %(conceptFrom)s does not reference a concept in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    conceptFrom=relationship.fromName)
                                relationshipSetValid = False
                            if relationship.toName and relationship.toConcept is None:
                                self.modelVersReport.error("vercue:invalidConceptReference",
                                    _("%(event)s %(relSet)s relationship toConcept %(conceptTo)s does not reference a concept in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    conceptTo=relationship.toName)
                                relationshipSetValid = False
                            if relationshipSetValid: # test that relations exist
                                if relationship.fromRelationship is None:
                                    if relationship.toName:
                                        self.modelVersReport.error("verrelse:invalidRelationshipReference",
                                            _("%(event)s %(relSet)s no relationship found from fromConcept %(conceptFrom)s to toConcept %(conceptTo)s in its DTS"),
                                    modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                    conceptFrom=relationship.fromName, conceptTo=relationship.toName)
                                    else:
                                        self.modelVersReport.error("verrelse:invalidRelationshipReference",
                                            _("%(event)s %(relSet)s no relationship found fromConcept %(conceptFrom)s in its DTS"),
                                            modelObject=relSetChange, event=relSetChange.name, relSet=name,
                                            conceptFrom=relationship.fromName)
                                    

                        
            
            # check instance aspect changes
            for iaChange in versReport.instanceAspectChanges:
                for instAspects in (iaChange.fromAspects, iaChange.toAspects):
                    if instAspects is not None and instAspects.aspects:
                        dimAspectElts = {}
                        for aspect in instAspects.aspects:
                            dts = aspect.modelAspects.dts
                            if (aspect.localName in ("explicitDimension", "typedDimension") and aspect.concept is None):
                                self.modelVersReport.error("vercue:invalidConceptReference",
                                    _("%(event)s dimension %(dimension)s is not a concept in its DTS"),
                                    modelObject=aspect, event=iaChange.name, dimension=aspect.conceptName)
                            elif aspect.localName == "explicitDimension":
                                dimConcept = aspect.concept
                                if not dimConcept.isExplicitDimension:
                                    self.modelVersReport.error("verdime:invalidExplicitDimensionIdentifier",
                                        _("%(event)s dimension %(dimension)s is not an explicit dimension in its DTS"),
                                        modelObject=aspect, event=iaChange.name, dimension=aspect.conceptName)
                                if dimConcept in dimAspectElts:
                                    self.modelVersReport.error("verdime:duplicateExplicitDimensionAspect",
                                        _("%(event)s dimension %(dimension)s is duplicated in a single explicitDimension element"),
                                        modelObject=(aspect, dimAspectElts[dimConcept]), event=iaChange.name, dimension=aspect.conceptName)
                                else:
                                    dimAspectElts[dimConcept] = aspect
                            elif aspect.localName == "typedDimension":
                                dimConcept = aspect.concept
                                if not dimConcept.isTypedDimension:
                                    self.modelVersReport.error("verdime:invalidTypedDimensionIdentifier",
                                        _("%(event)s dimension %(dimension)s is not a typed dimension in its DTS"),
                                        modelObject=aspect, event=iaChange.name, dimension=aspect.conceptName)
                                if dimConcept in dimAspectElts:
                                    self.modelVersReport.error("verdime:duplicateTypedDimensionAspect",
                                        _("%(event)s dimension %(dimension)s is duplicated in a single explicitDimension element"),
                                        modelObject=(aspect, dimAspectElts[dimConcept]), event=iaChange.name, dimension=aspect.conceptName)
                                else:
                                    dimAspectElts[dimConcept] = aspect
                            if aspect.localName in ("explicitDimension", "concepts"):
                                for relatedConcept in aspect.relatedConcepts:
                                    conceptMdlObj = relatedConcept.concept
                                    if conceptMdlObj is None or not conceptMdlObj.isItem:
                                        self.modelVersReport.error("vercue:invalidConceptReference",
                                            _("%(event)s concept %(concept)s is not an item in its DTS"),
                                            modelObject=aspect, event=iaChange.name, concept=relatedConcept.conceptName)
                                    if relatedConcept.arcrole is not None:
                                        if (not XbrlConst.isStandardArcrole(relatedConcept.arcrole) and
                                            relatedConcept.arcrole not in dts.arcroleTypes):
                                            self.modelVersReport.error("verdime:invalidURI",
                                                _("%(event)s arcrole %(arcrole)s is not defined in its DTS"),
                                                modelObject=aspect, event=iaChange.name, arcrole=relatedConcept.arcrole)
                                        elif not any(arcrole == relatedConcept.arcrole
                                                     for arcrole, linkrole, linkqname, arcqname in dts.baseSets.keys()):
                                            self.modelVersReport.error("verdime:invalidURI",
                                                _("%(event)s arcrole %(arcrole)s is not used in its DTS"),
                                                modelObject=aspect, event=iaChange.name, linkrole=relatedConcept.arcrole)
                                    if relatedConcept.linkrole is not None:
                                        if (relatedConcept.linkrole != "http://www.xbrl.org/2003/role/link" and
                                            relatedConcept.linkrole not in dts.roleTypes):
                                            self.modelVersReport.error("verdime:invalidURI",
                                                _("%(event)s linkrole %(linkrole)s is not defined in its DTS"),
                                                modelObject=aspect, event=iaChange.name, linkrole=relatedConcept.linkrole)
                                        elif not any(linkrole == relatedConcept.linkrole
                                                     for arcrole, linkrole, linkqname, arcqname in dts.baseSets.keys()):
                                            self.modelVersReport.error("verdime:invalidURI",
                                                _("%(event)s linkrole %(linkrole)s is not used in its DTS"),
                                                modelObject=aspect, event=iaChange.name, linkrole=relatedConcept.linkrole)
                                    if (relatedConcept.arc is not None and 
                                        (relatedConcept.arc not in dts.qnameConcepts or
                                         (dts.qnameConcepts[relatedConcept.arc].type is not None and
                                          not dts.qnameConcepts[relatedConcept.arc].type.isDerivedFrom(XbrlConst.qnXlArcType)))):
                                        self.modelVersReport.error("verdime:invalidArcElement",
                                            _("%(event)s arc %(arc)s is not defined as an arc in its DTS"),
                                            modelObject=aspect, event=iaChange.name, arc=relatedConcept.arc)
                                    if (relatedConcept.link is not None and
                                        (relatedConcept.link not in dts.qnameConcepts or
                                         (dts.qnameConcepts[relatedConcept.link].type is not None and
                                          not dts.qnameConcepts[relatedConcept.link].type.isDerivedFrom(XbrlConst.qnXlExtendedType)))):
                                        self.modelVersReport.error("verdime:invalidLinkElement",
                                            _("%(event)s link %(link)s is not defined in its DTS"),
                                            modelObject=aspect, event=iaChange.name, link=relatedConcept.link)
            
        self.close()
Ejemplo n.º 32
0
def groupRelationshipLabel(arcrole):
    if isinstance(arcrole, (list,tuple)): # (group-name, [arcroles])
        arcroleName = arcrole[0]
    else:
        arcroleName = XbrlConst.baseSetArcroleLabel(arcrole)[1:]
    return arcroleName
Ejemplo n.º 33
0
def baseSetArcroles(modelXbrl):
    # returns sorted list of tuples of arcrole basename and uri
    return sorted(set((XbrlConst.baseSetArcroleLabel(b[0]),b[0]) for b in modelXbrl.baseSets.keys()))
Ejemplo n.º 34
0
def checkFilingDTS(val, modelDocument, isEFM, isGFM, visited):
    global targetNamespaceDatePattern, efmFilenamePattern, htmlFileNamePattern, roleTypePattern, arcroleTypePattern, \
            arcroleDefinitionPattern, namePattern, linkroleDefinitionBalanceIncomeSheet, \
            namespacesConflictPattern
    if targetNamespaceDatePattern is None:
        targetNamespaceDatePattern = re.compile(
            r"/([12][0-9]{3})-([01][0-9])-([0-3][0-9])|"
            r"/([12][0-9]{3})([01][0-9])([0-3][0-9])|")
        efmFilenamePattern = re.compile(
            r"^[a-z0-9][a-zA-Z0-9_\.\-]*(\.xsd|\.xml|\.htm)$")
        htmlFileNamePattern = re.compile(
            r"^[a-zA-Z0-9][._a-zA-Z0-9-]*(\.htm)$")
        roleTypePattern = re.compile(r"^.*/role/[^/\s]+$")
        arcroleTypePattern = re.compile(r"^.*/arcrole/[^/\s]+$")
        arcroleDefinitionPattern = re.compile(
            r"^.*[^\\s]+.*$")  # at least one non-whitespace character
        namePattern = re.compile(
            "[][()*+?\\\\/^{}|@#%^=~`\"';:,<>&$\u00a3\u20ac]"
        )  # u20ac=Euro, u00a3=pound sterling
        linkroleDefinitionBalanceIncomeSheet = re.compile(
            r"[^-]+-\s+Statement\s+-\s+.*(income|balance|financial\W+position)",
            re.IGNORECASE)
        namespacesConflictPattern = re.compile(
            r"http://(xbrl\.us|fasb\.org|xbrl\.sec\.gov)/(dei|us-types|us-roles|rr)/([0-9]{4}-[0-9]{2}-[0-9]{2})$"
        )
    nonDomainItemNameProblemPattern = re.compile(
        r"({0})|(FirstQuarter|SecondQuarter|ThirdQuarter|FourthQuarter|[1-4]Qtr|Qtr[1-4]|ytd|YTD|HalfYear)(?:$|[A-Z\W])"
        .format(re.sub(r"\W", "", (val.entityRegistrantName or "").title())))

    visited.append(modelDocument)
    for referencedDocument, modelDocumentReference in modelDocument.referencesDocument.items(
    ):
        #6.07.01 no includes
        if modelDocumentReference.referenceType == "include":
            val.modelXbrl.error(
                ("EFM.6.07.01", "GFM.1.03.01"),
                _("Taxonomy schema %(schema)s includes %(include)s, only import is allowed"
                  ),
                modelObject=modelDocumentReference.referringModelObject,
                schema=os.path.basename(modelDocument.uri),
                include=os.path.basename(referencedDocument.uri))
        if referencedDocument not in visited and referencedDocument.inDTS:  # ignore EdgarRenderer added non-DTS documents
            checkFilingDTS(val, referencedDocument, isEFM, isGFM, visited)

    if val.disclosureSystem.standardTaxonomiesDict is None:
        pass

    if isEFM:
        if modelDocument.uri in val.disclosureSystem.standardTaxonomiesDict:
            if modelDocument.targetNamespace:
                # check for duplicates of us-types, dei, and rr taxonomies
                match = namespacesConflictPattern.match(
                    modelDocument.targetNamespace)
                if match is not None:
                    val.standardNamespaceConflicts[match.group(2)].add(
                        modelDocument)
        else:
            if len(modelDocument.basename) > 32:
                val.modelXbrl.error(
                    "EFM.5.01.01.tooManyCharacters",
                    _("Document file name %(filename)s must not exceed 32 characters."
                      ),
                    modelObject=modelDocument,
                    filename=modelDocument.basename)
            if modelDocument.type == ModelDocument.Type.INLINEXBRL:
                if not htmlFileNamePattern.match(modelDocument.basename):
                    val.modelXbrl.error(
                        "EFM.5.01.01",
                        _("Document file name %(filename)s must start with a-z or 0-9, contain upper or lower case letters, ., -, _, and end with .htm."
                          ),
                        modelObject=modelDocument,
                        filename=modelDocument.basename)
            elif not efmFilenamePattern.match(modelDocument.basename):
                val.modelXbrl.error(
                    "EFM.5.01.01",
                    _("Document file name %(filename)s must start with a-z or 0-9, contain upper or lower case letters, ., -, _, and end with .xsd or .xml."
                      ),
                    modelObject=modelDocument,
                    filename=modelDocument.basename)

    if (modelDocument.type == ModelDocument.Type.SCHEMA
            and modelDocument.targetNamespace
            not in val.disclosureSystem.baseTaxonomyNamespaces
            and modelDocument.uri.startswith(val.modelXbrl.uriDir)):

        val.hasExtensionSchema = True
        # check schema contents types
        # 6.7.3 check namespace for standard authority
        targetNamespaceAuthority = UrlUtil.authority(
            modelDocument.targetNamespace)
        if targetNamespaceAuthority in val.disclosureSystem.standardAuthorities:
            val.modelXbrl.error(
                ("EFM.6.07.03", "GFM.1.03.03"),
                _("Taxonomy schema %(schema)s namespace %(targetNamespace)s is a disallowed authority"
                  ),
                modelObject=modelDocument,
                schema=os.path.basename(modelDocument.uri),
                targetNamespace=modelDocument.targetNamespace,
                targetNamespaceAuthority=UrlUtil.authority(
                    modelDocument.targetNamespace, includeScheme=False))

        # 6.7.4 check namespace format
        if modelDocument.targetNamespace is None or not modelDocument.targetNamespace.startswith(
                "http://"):
            match = None
        else:
            targetNamespaceDate = modelDocument.targetNamespace[
                len(targetNamespaceAuthority):]
            match = targetNamespaceDatePattern.match(targetNamespaceDate)
        if match is not None:
            try:
                if match.lastindex == 3:
                    date = datetime.date(int(match.group(1)),
                                         int(match.group(2)),
                                         int(match.group(3)))
                elif match.lastindex == 6:
                    date = datetime.date(int(match.group(4)),
                                         int(match.group(5)),
                                         int(match.group(6)))
                else:
                    match = None
            except ValueError:
                match = None
        if match is None:
            val.modelXbrl.error(
                ("EFM.6.07.04", "GFM.1.03.04"),
                _("Taxonomy schema %(schema)s namespace %(targetNamespace)s must have format http://{authority}/{versionDate}"
                  ),
                modelObject=modelDocument,
                schema=os.path.basename(modelDocument.uri),
                targetNamespace=modelDocument.targetNamespace)
        elif val.fileNameDate and date > val.fileNameDate:
            val.modelXbrl.info(
                ("EFM.6.07.06", "GFM.1.03.06"),
                _("Warning: Taxonomy schema %(schema)s namespace %(targetNamespace)s has date later than document name date %(docNameDate)s"
                  ),
                modelObject=modelDocument,
                schema=os.path.basename(modelDocument.uri),
                targetNamespace=modelDocument.targetNamespace,
                docNameDate=val.fileNameDate)

        if modelDocument.targetNamespace is not None:
            # 6.7.5 check prefix for _
            authority = UrlUtil.authority(modelDocument.targetNamespace)
            if not re.match(r"(http://|https://|ftp://|urn:)\w+", authority):
                val.modelXbrl.error(
                    ("EFM.6.07.05", "GFM.1.03.05"),
                    _("Taxonomy schema %(schema)s namespace %(targetNamespace)s must be a valid URL with a valid authority for the namespace."
                      ),
                    modelObject=modelDocument,
                    schema=os.path.basename(modelDocument.uri),
                    targetNamespace=modelDocument.targetNamespace)
            prefix = XmlUtil.xmlnsprefix(modelDocument.xmlRootElement,
                                         modelDocument.targetNamespace)
            if not prefix:
                val.modelXbrl.error(
                    ("EFM.6.07.07", "GFM.1.03.07"),
                    _("Taxonomy schema %(schema)s namespace %(targetNamespace)s missing prefix for the namespace."
                      ),
                    modelObject=modelDocument,
                    schema=os.path.basename(modelDocument.uri),
                    targetNamespace=modelDocument.targetNamespace)
            elif "_" in prefix:
                val.modelXbrl.error(
                    ("EFM.6.07.07", "GFM.1.03.07"),
                    _("Taxonomy schema %(schema)s namespace %(targetNamespace)s prefix %(prefix)s must not have an '_'"
                      ),
                    modelObject=modelDocument,
                    schema=os.path.basename(modelDocument.uri),
                    targetNamespace=modelDocument.targetNamespace,
                    prefix=prefix)

            for modelConcept in modelDocument.xmlRootElement.iterdescendants(
                    tag="{http://www.w3.org/2001/XMLSchema}element"):
                if isinstance(modelConcept, ModelConcept):
                    # 6.7.16 name not duplicated in standard taxonomies
                    name = modelConcept.get("name")
                    if name is None:
                        name = ""
                        if modelConcept.get("ref") is not None:
                            continue  # don't validate ref's here
                    for c in val.modelXbrl.nameConcepts.get(name, []):
                        if c.modelDocument != modelDocument:
                            if not c.modelDocument.uri.startswith(
                                    val.modelXbrl.uriDir):
                                val.modelXbrl.error(
                                    ("EFM.6.07.16", "GFM.1.03.18"),
                                    _("Concept %(concept)s is also defined in standard taxonomy schema schema %(standardSchema)s"
                                      ),
                                    modelObject=(modelConcept, c),
                                    concept=modelConcept.qname,
                                    standardSchema=os.path.basename(
                                        c.modelDocument.uri),
                                    standardConcept=c.qname)

                    # 6.7.17 id properly formed
                    _id = modelConcept.id
                    requiredId = (prefix
                                  if prefix is not None else "") + "_" + name
                    if _id != requiredId:
                        val.modelXbrl.error(
                            ("EFM.6.07.17", "GFM.1.03.19"),
                            _("Concept %(concept)s id %(id)s should be %(requiredId)s"
                              ),
                            modelObject=modelConcept,
                            concept=modelConcept.qname,
                            id=_id,
                            requiredId=requiredId)

                    # 6.7.18 nillable is true
                    nillable = modelConcept.get("nillable")
                    if nillable != "true" and modelConcept.isItem:
                        val.modelXbrl.error(
                            ("EFM.6.07.18", "GFM.1.03.20"),
                            _("Taxonomy schema %(schema)s element %(concept)s nillable %(nillable)s should be 'true'"
                              ),
                            modelObject=modelConcept,
                            schema=os.path.basename(modelDocument.uri),
                            concept=name,
                            nillable=nillable)

                    # 6.7.19 not tuple
                    if modelConcept.isTuple:
                        val.modelXbrl.error(
                            ("EFM.6.07.19", "GFM.1.03.21"),
                            _("Concept %(concept)s is a tuple"),
                            modelObject=modelConcept,
                            concept=modelConcept.qname)

                    # 6.7.20 no typed domain ref
                    if modelConcept.isTypedDimension:
                        val.modelXbrl.error(
                            ("EFM.6.07.20", "GFM.1.03.22"),
                            _("Concept %(concept)s has typedDomainRef %(typedDomainRef)s"
                              ),
                            modelObject=modelConcept,
                            concept=modelConcept.qname,
                            typedDomainRef=modelConcept.typedDomainElement.
                            qname if modelConcept.typedDomainElement
                            is not None else modelConcept.typedDomainRef)

                    # 6.7.21 abstract must be duration
                    isDuration = modelConcept.periodType == "duration"
                    if modelConcept.isAbstract and not isDuration:
                        val.modelXbrl.error(
                            ("EFM.6.07.21", "GFM.1.03.23"),
                            _("Taxonomy schema %(schema)s element %(concept)s is abstract but period type is not duration"
                              ),
                            modelObject=modelConcept,
                            schema=os.path.basename(modelDocument.uri),
                            concept=modelConcept.qname)

                    # 6.7.22 abstract must be stringItemType
                    ''' removed SEC EFM v.17, Edgar release 10.4, and GFM 2011-04-08
                    if modelConcept.abstract == "true" and modelConcept.typeQname != XbrlConst. qnXbrliStringItemType:
                        val.modelXbrl.error(("EFM.6.07.22", "GFM.1.03.24"),
                            _("Concept %(concept)s  is abstract but type is not xbrli:stringItemType"),
                            modelObject=modelConcept, concept=modelConcept.qname)
					'''
                    substitutionGroupQname = modelConcept.substitutionGroupQname
                    # 6.7.23 Axis must be subs group dimension
                    if name.endswith("Axis") ^ (
                            substitutionGroupQname
                            == XbrlConst.qnXbrldtDimensionItem):
                        val.modelXbrl.error(
                            ("EFM.6.07.23", "GFM.1.03.25"),
                            _("Concept %(concept)s must end in Axis to be in xbrldt:dimensionItem substitution group"
                              ),
                            modelObject=modelConcept,
                            concept=modelConcept.qname)

                    # 6.7.24 Table must be subs group hypercube
                    if name.endswith("Table") ^ (
                            substitutionGroupQname
                            == XbrlConst.qnXbrldtHypercubeItem):
                        val.modelXbrl.error(
                            ("EFM.6.07.24", "GFM.1.03.26"),
                            _("Concept %(concept)s must end in Table to be in xbrldt:hypercubeItem substitution group"
                              ),
                            modelObject=modelConcept,
                            schema=os.path.basename(modelDocument.uri),
                            concept=modelConcept.qname)

                    # 6.7.25 if neither hypercube or dimension, substitution group must be item
                    if substitutionGroupQname not in (
                            None, XbrlConst.qnXbrldtDimensionItem,
                            XbrlConst.qnXbrldtHypercubeItem,
                            XbrlConst.qnXbrliItem):
                        val.modelXbrl.error(
                            ("EFM.6.07.25", "GFM.1.03.27"),
                            _("Concept %(concept)s has disallowed substitution group %(substitutionGroup)s"
                              ),
                            modelObject=modelConcept,
                            concept=modelConcept.qname,
                            substitutionGroup=modelConcept.
                            substitutionGroupQname)

                    # 6.7.26 Table must be subs group hypercube
                    if name.endswith(
                            "LineItems") and modelConcept.abstract != "true":
                        val.modelXbrl.error(
                            ("EFM.6.07.26", "GFM.1.03.28"),
                            _("Concept %(concept)s is a LineItems but not abstract"
                              ),
                            modelObject=modelConcept,
                            concept=modelConcept.qname)

                    # 6.7.27 type domainMember must end with Domain or Member
                    conceptType = modelConcept.type
                    isDomainItemType = conceptType is not None and conceptType.isDomainItemType
                    endsWithDomainOrMember = name.endswith(
                        "Domain") or name.endswith("Member")
                    if isDomainItemType != endsWithDomainOrMember:
                        val.modelXbrl.error(
                            ("EFM.6.07.27", "GFM.1.03.29"),
                            _("Concept %(concept)s must end with Domain or Member for type of domainItemType"
                              ),
                            modelObject=modelConcept,
                            concept=modelConcept.qname)

                    # 6.7.28 domainItemType must be duration
                    if isDomainItemType and not isDuration:
                        val.modelXbrl.error(
                            ("EFM.6.07.28", "GFM.1.03.30"),
                            _("Concept %(concept)s is a domainItemType and must be periodType duration"
                              ),
                            modelObject=modelConcept,
                            concept=modelConcept.qname)

                    #6.7.31 (version 27) fractions
                    if modelConcept.isFraction:
                        val.modelXbrl.error(
                            "EFM.6.07.31",
                            _("Concept %(concept)s is a fraction"),
                            modelObject=modelConcept,
                            concept=modelConcept.qname)

                    #6.7.32 (version 27) instant non numeric
                    if modelConcept.isItem and (not modelConcept.isNumeric
                                                and not isDuration
                                                and not modelConcept.isAbstract
                                                and not isDomainItemType):
                        val.modelXbrl.error(
                            "EFM.6.07.32",
                            _("Taxonomy schema %(schema)s element %(concept)s is non-numeric but period type is not duration"
                              ),
                            modelObject=modelConcept,
                            schema=os.path.basename(modelDocument.uri),
                            concept=modelConcept.qname)

                    # 6.8.5 semantic check, check LC3 name
                    if name:
                        if not name[0].isupper():
                            val.modelXbrl.log(
                                "ERROR-SEMANTIC", ("EFM.6.08.05.firstLetter",
                                                   "GFM.2.03.05.firstLetter"),
                                _("Concept %(concept)s name must start with a capital letter"
                                  ),
                                modelObject=modelConcept,
                                concept=modelConcept.qname)
                        if namePattern.search(name):
                            val.modelXbrl.log(
                                "ERROR-SEMANTIC",
                                ("EFM.6.08.05.disallowedCharacter",
                                 "GFM.2.03.05.disallowedCharacter"),
                                _("Concept %(concept)s has disallowed name character"
                                  ),
                                modelObject=modelConcept,
                                concept=modelConcept.qname)
                        if len(name) > 200:
                            val.modelXbrl.log(
                                "ERROR-SEMANTIC",
                                "EFM.6.08.05.nameLength",
                                _("Concept %(concept)s name length %(namelength)s exceeds 200 characters"
                                  ),
                                modelObject=modelConcept,
                                concept=modelConcept.qname,
                                namelength=len(name))

                    if isEFM:
                        label = modelConcept.label(lang="en-US",
                                                   fallbackToQname=False)
                        if label:
                            # allow Joe's Bar, N.A.  to be JoesBarNA -- remove ', allow A. as not article "a"
                            lc3name = ''.join(
                                re.sub(r"['.-]", "", (
                                    w[0] or w[2] or w[3] or w[4])).title()
                                for w in re.findall(
                                    r"((\w+')+\w+)|(A[.-])|([.-]A(?=\W|$))|(\w+)",
                                    label
                                )  # EFM implies this should allow - and . re.findall(r"[\w\-\.]+", label)
                                if w[4].lower() not in ("the", "a", "an"))
                            if not (name == lc3name or
                                    (name and lc3name and lc3name[0].isdigit()
                                     and name[1:] == lc3name and
                                     (name[0].isalpha() or name[0] == '_'))):
                                val.modelXbrl.log(
                                    "WARNING-SEMANTIC",
                                    "EFM.6.08.05.LC3",
                                    _("Concept %(concept)s should match expected LC3 composition %(lc3name)s"
                                      ),
                                    modelObject=modelConcept,
                                    concept=modelConcept.qname,
                                    lc3name=lc3name)

                    if conceptType is not None:
                        # 6.8.6 semantic check
                        if not isDomainItemType and conceptType.qname != XbrlConst.qnXbrliDurationItemType:
                            nameProblems = nonDomainItemNameProblemPattern.findall(
                                name)
                            if any(
                                    any(t) for t in nameProblems
                            ):  # list of tuples with possibly nonempty strings
                                val.modelXbrl.log(
                                    "WARNING-SEMANTIC",
                                    ("EFM.6.08.06", "GFM.2.03.06"),
                                    _("Concept %(concept)s should not contain company or period information, found: %(matches)s"
                                      ),
                                    modelObject=modelConcept,
                                    concept=modelConcept.qname,
                                    matches=", ".join(''.join(t)
                                                      for t in nameProblems))

                        if conceptType.qname == XbrlConst.qnXbrliMonetaryItemType:
                            if not modelConcept.balance:
                                # 6.8.11 may not appear on a income or balance statement
                                if any(
                                        linkroleDefinitionBalanceIncomeSheet.
                                        match(roleType.definition)
                                        for rel in val.modelXbrl.
                                        relationshipSet(XbrlConst.parentChild).
                                        toModelObject(modelConcept)
                                        for roleType in val.modelXbrl.
                                        roleTypes.get(rel.linkrole, ())):
                                    val.modelXbrl.log(
                                        "ERROR-SEMANTIC",
                                        ("EFM.6.08.11", "GFM.2.03.11"),
                                        _("Concept %(concept)s must have a balance because it appears in a statement of income or balance sheet"
                                          ),
                                        modelObject=modelConcept,
                                        concept=modelConcept.qname)
                                # 6.11.5 semantic check, must have a documentation label
                                stdLabel = modelConcept.label(
                                    lang="en-US", fallbackToQname=False)
                                defLabel = modelConcept.label(
                                    preferredLabel=XbrlConst.
                                    documentationLabel,
                                    lang="en-US",
                                    fallbackToQname=False)
                                if not defLabel or (  # want different words than std label
                                        stdLabel
                                        and re.findall(r"\w+", stdLabel)
                                        == re.findall(r"\w+", defLabel)):
                                    val.modelXbrl.log(
                                        "ERROR-SEMANTIC",
                                        ("EFM.6.11.05", "GFM.2.04.04"),
                                        _("Concept %(concept)s is monetary without a balance and must have a documentation label that disambiguates its sign"
                                          ),
                                        modelObject=modelConcept,
                                        concept=modelConcept.qname)

                        # 6.8.16 semantic check
                        if conceptType.qname == XbrlConst.qnXbrliDateItemType and modelConcept.periodType != "duration":
                            val.modelXbrl.log(
                                "ERROR-SEMANTIC",
                                ("EFM.6.08.16", "GFM.2.03.16"),
                                _("Concept %(concept)s of type xbrli:dateItemType must have periodType duration"
                                  ),
                                modelObject=modelConcept,
                                concept=modelConcept.qname)

                        # 6.8.17 semantic check
                        if conceptType.qname == XbrlConst.qnXbrliStringItemType and modelConcept.periodType != "duration":
                            val.modelXbrl.log(
                                "ERROR-SEMANTIC",
                                ("EFM.6.08.17", "GFM.2.03.17"),
                                _("Concept %(concept)s of type xbrli:stringItemType must have periodType duration"
                                  ),
                                modelObject=modelConcept,
                                concept=modelConcept.qname)

        # 6.7.8 check for embedded linkbase
        for e in modelDocument.xmlRootElement.iterdescendants(
                tag="{http://www.xbrl.org/2003/linkbase}linkbase"):
            if isinstance(e, ModelObject):
                val.modelXbrl.error(
                    ("EFM.6.07.08", "GFM.1.03.08"),
                    _("Taxonomy schema %(schema)s contains an embedded linkbase"
                      ),
                    modelObject=e,
                    schema=modelDocument.basename)
                break

        requiredUsedOns = {
            XbrlConst.qnLinkPresentationLink, XbrlConst.qnLinkCalculationLink,
            XbrlConst.qnLinkDefinitionLink
        }

        standardUsedOns = {
            XbrlConst.qnLinkLabel,
            XbrlConst.qnLinkReference,
            XbrlConst.qnLinkDefinitionArc,
            XbrlConst.qnLinkCalculationArc,
            XbrlConst.qnLinkPresentationArc,
            XbrlConst.qnLinkLabelArc,
            XbrlConst.qnLinkReferenceArc,
            # per WH, private footnote arc and footnore resource roles are not allowed
            XbrlConst.qnLinkFootnoteArc,
            XbrlConst.qnLinkFootnote,
        }

        # 6.7.9 role types authority
        for e in modelDocument.xmlRootElement.iterdescendants(
                tag="{http://www.xbrl.org/2003/linkbase}roleType"):
            if isinstance(e, ModelObject):
                roleURI = e.get("roleURI")
                if targetNamespaceAuthority != UrlUtil.authority(roleURI):
                    val.modelXbrl.error(
                        ("EFM.6.07.09", "GFM.1.03.09"),
                        _("RoleType %(roleType)s does not match authority %(targetNamespaceAuthority)s"
                          ),
                        modelObject=e,
                        roleType=roleURI,
                        targetNamespaceAuthority=targetNamespaceAuthority,
                        targetNamespace=modelDocument.targetNamespace)
                # 6.7.9 end with .../role/lc3 name
                if not roleTypePattern.match(roleURI):
                    val.modelXbrl.warning(
                        ("EFM.6.07.09.roleEnding", "GFM.1.03.09"),
                        "RoleType %(roleType)s should end with /role/{LC3name}",
                        modelObject=e,
                        roleType=roleURI)

                # 6.7.10 only one role type declaration in DTS
                modelRoleTypes = val.modelXbrl.roleTypes.get(roleURI)
                if modelRoleTypes is not None:
                    modelRoleType = modelRoleTypes[0]
                    definition = modelRoleType.definitionNotStripped
                    usedOns = modelRoleType.usedOns
                    if len(modelRoleTypes) == 1:
                        # 6.7.11 used on's for pre, cal, def if any has a used on
                        if not usedOns.isdisjoint(requiredUsedOns) and len(
                                requiredUsedOns - usedOns) > 0:
                            val.modelXbrl.error(
                                ("EFM.6.07.11", "GFM.1.03.11"),
                                _("RoleType %(roleType)s missing used on %(usedOn)s"
                                  ),
                                modelObject=e,
                                roleType=roleURI,
                                usedOn=requiredUsedOns - usedOns)

                        # 6.7.12 definition match pattern
                        if (val.disclosureSystem.roleDefinitionPattern
                                is not None and
                            (definition is None or not val.disclosureSystem.
                             roleDefinitionPattern.match(definition))):
                            val.modelXbrl.error(
                                ("EFM.6.07.12", "GFM.1.03.12-14"),
                                _("RoleType %(roleType)s definition \"%(definition)s\" must match {Sortcode} - {Type} - {Title}"
                                  ),
                                modelObject=e,
                                roleType=roleURI,
                                definition=(definition or ""))

                    if usedOns & standardUsedOns:  # semantics check
                        val.modelXbrl.log(
                            "ERROR-SEMANTIC", ("EFM.6.08.03", "GFM.2.03.03"),
                            _("RoleType %(roleuri)s is defined using role types already defined by standard roles for: %(qnames)s"
                              ),
                            modelObject=e,
                            roleuri=roleURI,
                            qnames=', '.join(
                                str(qn) for qn in usedOns & standardUsedOns))

        # 6.7.13 arcrole types authority
        for e in modelDocument.xmlRootElement.iterdescendants(
                tag="{http://www.xbrl.org/2003/linkbase}arcroleType"):
            if isinstance(e, ModelObject):
                arcroleURI = e.get("arcroleURI")
                if targetNamespaceAuthority != UrlUtil.authority(arcroleURI):
                    val.modelXbrl.error(
                        ("EFM.6.07.13", "GFM.1.03.15"),
                        _("ArcroleType %(arcroleType)s does not match authority %(targetNamespaceAuthority)s"
                          ),
                        modelObject=e,
                        arcroleType=arcroleURI,
                        targetNamespaceAuthority=targetNamespaceAuthority,
                        targetNamespace=modelDocument.targetNamespace)
                # 6.7.13 end with .../arcrole/lc3 name
                if not arcroleTypePattern.match(arcroleURI):
                    val.modelXbrl.warning(
                        ("EFM.6.07.13.arcroleEnding", "GFM.1.03.15"),
                        _("ArcroleType %(arcroleType)s should end with /arcrole/{LC3name}"
                          ),
                        modelObject=e,
                        arcroleType=arcroleURI)

                # 6.7.15 definition match pattern
                modelRoleTypes = val.modelXbrl.arcroleTypes[arcroleURI]
                definition = modelRoleTypes[0].definition
                if definition is None or not arcroleDefinitionPattern.match(
                        definition):
                    val.modelXbrl.error(
                        ("EFM.6.07.15", "GFM.1.03.17"),
                        _("ArcroleType %(arcroleType)s definition must be non-empty"
                          ),
                        modelObject=e,
                        arcroleType=arcroleURI)

                # semantic checks
                usedOns = modelRoleTypes[0].usedOns
                if usedOns & standardUsedOns:  # semantics check
                    val.modelXbrl.log(
                        "ERROR-SEMANTIC", ("EFM.6.08.03", "GFM.2.03.03"),
                        _("ArcroleType %(arcroleuri)s is defined using role types already defined by standard arcroles for: %(qnames)s"
                          ),
                        modelObject=e,
                        arcroleuri=arcroleURI,
                        qnames=', '.join(
                            str(qn) for qn in usedOns & standardUsedOns))

        #6.3.3 filename check
        m = re.match(r"^\w+-([12][0-9]{3}[01][0-9][0-3][0-9]).xsd$",
                     modelDocument.basename)
        if m:
            try:  # check date value
                datetime.datetime.strptime(m.group(1), "%Y%m%d").date()
                # date and format are ok, check "should" part of 6.3.3
                if val.fileNameBasePart:
                    expectedFilename = "{0}-{1}.xsd".format(
                        val.fileNameBasePart, val.fileNameDatePart)
                    if modelDocument.basename != expectedFilename:
                        val.modelXbrl.log(
                            "WARNING-SEMANTIC", ("EFM.6.03.03.matchInstance",
                                                 "GFM.1.01.01.matchInstance"),
                            _('Schema file name warning: %(filename)s, should match %(expectedFilename)s'
                              ),
                            modelObject=modelDocument,
                            filename=modelDocument.basename,
                            expectedFilename=expectedFilename)
            except ValueError:
                val.modelXbrl.error(
                    (val.EFM60303, "GFM.1.01.01"),
                    _('Invalid schema file base name part (date) in "{base}-{yyyymmdd}.xsd": %(filename)s'
                      ),
                    modelObject=modelDocument,
                    filename=modelDocument.basename,
                    messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))
        else:
            val.modelXbrl.error(
                (val.EFM60303, "GFM.1.01.01"),
                _('Invalid schema file name, must match "{base}-{yyyymmdd}.xsd": %(filename)s'
                  ),
                modelObject=modelDocument,
                filename=modelDocument.basename,
                messageCodes=("EFM.6.03.03", "EFM.6.23.01", "GFM.1.01.01"))

    elif modelDocument.type == ModelDocument.Type.LINKBASE:
        # if it is part of the submission (in same directory) check name
        labelRels = None
        if modelDocument.filepath.startswith(
                val.modelXbrl.modelDocument.filepathdir):
            #6.3.3 filename check
            extLinkElt = XmlUtil.descendant(
                modelDocument.xmlRootElement, XbrlConst.link, "*",
                "{http://www.w3.org/1999/xlink}type", "extended")
            if extLinkElt is None:  # no ext link element
                val.modelXbrl.error(
                    (val.EFM60303 + ".noLinkElement",
                     "GFM.1.01.01.noLinkElement"),
                    _('Invalid linkbase file name: %(filename)s, has no extended link element, cannot determine link type.'
                      ),
                    modelObject=modelDocument,
                    filename=modelDocument.basename,
                    messageCodes=("EFM.6.03.03.noLinkElement",
                                  "EFM.6.23.01.noLinkElement",
                                  "GFM.1.01.01.noLinkElement"))
            elif extLinkElt.localName not in extLinkEltFileNameEnding:
                val.modelXbrl.error(
                    "EFM.6.03.02",
                    _('Invalid linkbase link element %(linkElement)s in %(filename)s'
                      ),
                    modelObject=modelDocument,
                    linkElement=extLinkElt.localName,
                    filename=modelDocument.basename)
            else:
                m = re.match(
                    r"^\w+-([12][0-9]{3}[01][0-9][0-3][0-9])(_[a-z]{3}).xml$",
                    modelDocument.basename)
                expectedSuffix = extLinkEltFileNameEnding[extLinkElt.localName]
                if m and m.group(2) == expectedSuffix:
                    try:  # check date value
                        datetime.datetime.strptime(m.group(1), "%Y%m%d").date()
                        # date and format are ok, check "should" part of 6.3.3
                        if val.fileNameBasePart:
                            expectedFilename = "{0}-{1}{2}.xml".format(
                                val.fileNameBasePart, val.fileNameDatePart,
                                expectedSuffix)
                            if modelDocument.basename != expectedFilename:
                                val.modelXbrl.log(
                                    "WARNING-SEMANTIC",
                                    ("EFM.6.03.03.matchInstance",
                                     "GFM.1.01.01.matchInstance"),
                                    _('Linkbase name warning: %(filename)s should match %(expectedFilename)s'
                                      ),
                                    modelObject=modelDocument,
                                    filename=modelDocument.basename,
                                    expectedFilename=expectedFilename)
                    except ValueError:
                        val.modelXbrl.error(
                            (val.EFM60303, "GFM.1.01.01"),
                            _('Invalid linkbase base file name part (date) in "{base}-{yyyymmdd}_{suffix}.xml": %(filename)s'
                              ),
                            modelObject=modelDocument,
                            filename=modelDocument.basename,
                            messageCodes=("EFM.6.03.03", "EFM.6.23.01",
                                          "GFM.1.01.01"))
                else:
                    val.modelXbrl.error(
                        (val.EFM60303, "GFM.1.01.01"),
                        _('Invalid linkbase name, must match "{base}-{yyyymmdd}%(expectedSuffix)s.xml": %(filename)s'
                          ),
                        modelObject=modelDocument,
                        filename=modelDocument.basename,
                        expectedSuffix=expectedSuffix,
                        messageCodes=("EFM.6.03.03", "EFM.6.23.01",
                                      "GFM.1.01.01"))
                if extLinkElt.localName == "labelLink":
                    if labelRels is None:
                        labelRels = val.modelXbrl.relationshipSet(
                            XbrlConst.conceptLabel)
                    for labelElt in XmlUtil.children(extLinkElt,
                                                     XbrlConst.link, "label"):
                        # 6.10.9
                        if XbrlConst.isNumericRole(labelElt.role):
                            for rel in labelRels.toModelObject(labelElt):
                                if rel.fromModelObject is not None and not rel.fromModelObject.isNumeric:
                                    val.modelXbrl.error(
                                        "EFM.6.10.09",
                                        _("Label of non-numeric concept %(concept)s has a numeric role: %(role)s"
                                          ),
                                        modelObject=(labelElt,
                                                     rel.fromModelObject),
                                        concept=rel.fromModelObject.qname,
                                        role=labelElt.role)
Ejemplo n.º 35
0
def init(modelXbrl):
    # setup modelXbrl for rendering evaluation

    # dimension defaults required in advance of validation
    from arelle import ValidateXbrlDimensions, ValidateFormula, ModelDocument
    ValidateXbrlDimensions.loadDimensionDefaults(modelXbrl)

    hasXbrlTables = False

    # validate table linkbase dimensions
    for baseSetKey in modelXbrl.baseSets.keys():
        arcrole, ELR, linkqname, arcqname = baseSetKey
        if ELR and linkqname and arcqname and XbrlConst.isTableRenderingArcrole(
                arcrole):
            ValidateFormula.checkBaseSet(
                modelXbrl, arcrole, ELR,
                modelXbrl.relationshipSet(arcrole, ELR, linkqname, arcqname))
            if arcrole in (XbrlConst.tableBreakdown,
                           XbrlConst.tableBreakdownMMDD,
                           XbrlConst.tableBreakdown201305,
                           XbrlConst.tableBreakdown201301,
                           XbrlConst.tableAxis2011):
                hasXbrlTables = True

    # provide context for view
    if modelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE:
        instance = None  # use instance of the entry pont
    else:  # need dummy instance
        instance = ModelDocument.create(
            modelXbrl,
            ModelDocument.Type.INSTANCE,
            "dummy.xml",  # fake URI and fake schemaRef 
            ("http://www.xbrl.org/2003/xbrl-instance-2003-12-31.xsd", ))

    if hasXbrlTables:
        # formula processor is needed for 2011 XBRL tables but not for 2010 Eurofiling tables
        modelXbrl.rendrCntx = XPathContext.create(modelXbrl, instance)

        modelXbrl.profileStat(None)

        # setup fresh parameters from formula options
        modelXbrl.parameters = modelXbrl.modelManager.formulaOptions.typedParameters(
        )

        # validate parameters and custom function signatures
        ValidateFormula.validate(modelXbrl,
                                 xpathContext=modelXbrl.rendrCntx,
                                 parametersOnly=True,
                                 statusMsg=_("compiling rendering tables"))

        # deprecated as of 2013-05-17
        # check and extract message expressions into compilable programs
        for msgArcrole in (XbrlConst.tableDefinitionNodeMessage201301,
                           XbrlConst.tableDefinitionNodeSelectionMessage201301,
                           XbrlConst.tableAxisMessage2011,
                           XbrlConst.tableAxisSelectionMessage2011):
            for msgRel in modelXbrl.relationshipSet(
                    msgArcrole).modelRelationships:
                ValidateFormula.checkMessageExpressions(
                    modelXbrl, msgRel.toModelObject)

        # compile and validate tables
        for modelTable in modelXbrl.modelRenderingTables:
            modelTable.fromInstanceQnames = None  # required if referred to by variables scope chaining
            modelTable.compile()

            hasNsWithAspectModel = modelTable.namespaceURI in (
                XbrlConst.euRend, XbrlConst.table2011, XbrlConst.table201301,
                XbrlConst.table201305)

            # check aspectModel  (attribute removed 2013-06, now always dimensional)
            if modelTable.aspectModel not in (
                    "non-dimensional", "dimensional") and hasNsWithAspectModel:
                modelXbrl.error(
                    "xbrlte:unknownAspectModel",
                    _("Table %(xlinkLabel)s, aspect model %(aspectModel)s not recognized"
                      ),
                    modelObject=modelTable,
                    xlinkLabel=modelTable.xlinkLabel,
                    aspectModel=modelTable.aspectModel)
            else:
                modelTable.priorAspectAxisDisposition = {}
                # check ordinate aspects against aspectModel
                oppositeAspectModel = (
                    _DICT_SET({'dimensional', 'non-dimensional'}) -
                    _DICT_SET({modelTable.aspectModel})).pop()
                if hasNsWithAspectModel:
                    uncoverableAspects = aspectModels[
                        oppositeAspectModel] - aspectModels[
                            modelTable.aspectModel]
                else:
                    uncoverableAspects = ()
                aspectsCovered = set()
                for tblAxisRel in modelXbrl.relationshipSet(
                    (XbrlConst.tableBreakdown, XbrlConst.tableBreakdownMMDD,
                     XbrlConst.tableBreakdown201305,
                     XbrlConst.tableBreakdown201301,
                     XbrlConst.tableAxis2011)).fromModelObject(modelTable):
                    breakdownAspectsCovered = set()
                    hasCoveredAspect = checkBreakdownDefinitionNode(
                        modelXbrl, modelTable, tblAxisRel,
                        tblAxisRel.axisDisposition, uncoverableAspects,
                        breakdownAspectsCovered)
                    ''' removed 2013-10
                    if not hasCoveredAspect:
                        definitionNode = tblAxisRel.toModelObject
                        modelXbrl.error("xbrlte:breakdownDefinesNoAspects",
                            _("Breakdown %(xlinkLabel)s has no participating aspects"),
                            modelObject=(modelTable,definitionNode), xlinkLabel=definitionNode.xlinkLabel, axis=definitionNode.localName)
                    '''
                    aspectsCovered |= breakdownAspectsCovered
                    checkBreakdownLeafNodeAspects(modelXbrl, modelTable,
                                                  tblAxisRel, set(),
                                                  breakdownAspectsCovered)
                if Aspect.CONCEPT not in aspectsCovered and not hasNsWithAspectModel:
                    modelXbrl.error(
                        "xbrlte:tableMissingConceptAspect",
                        _("Table %(xlinkLabel)s does not include the concept aspect as one of its participating aspects"
                          ),
                        modelObject=modelTable,
                        xlinkLabel=modelTable.xlinkLabel)
                del modelTable.priorAspectAxisDisposition
                # check for table-parameter name clash
                parameterNames = {}
                for tblParamRel in modelXbrl.relationshipSet(
                    (XbrlConst.tableParameter, XbrlConst.tableParameterMMDD
                     )).fromModelObject(modelTable):
                    parameterName = tblParamRel.variableQname
                    if parameterName in parameterNames:
                        modelXbrl.error(
                            "xbrlte:tableParameterNameClash ",
                            _("Table %(xlinkLabel)s has parameter name clash for variable %(name)s"
                              ),
                            modelObject=(modelTable, tblParamRel,
                                         parameterNames[parameterName]),
                            xlinkLabel=modelTable.xlinkLabel,
                            name=parameterName)
                    else:
                        parameterNames[parameterName] = tblParamRel

        modelXbrl.profileStat(_("compileTables"))
Ejemplo n.º 36
0
    def __init__(self,
                 modelXbrl,
                 arcrole,
                 linkrole=None,
                 linkqname=None,
                 arcqname=None,
                 includeProhibits=False):
        self.isChanged = False
        self.modelXbrl = modelXbrl
        self.arcrole = arcrole
        self.linkrole = linkrole
        self.linkqname = linkqname
        self.arcqname = arcqname

        baseSetKey = (arcrole, linkrole, linkqname, arcqname)
        relationshipSetKey = (arcrole, linkrole, linkqname, arcqname,
                              includeProhibits)

        # base sets does not care about the #includeProhibits
        if baseSetKey in self.modelXbrl.baseSets:
            modelLinks = self.modelXbrl.baseSets[baseSetKey]
        else:
            modelLinks = []

        # gather arcs
        relationships = {}
        isDimensionRel = self.arcrole == "XBRL-dimensions"  # all dimensional relationship arcroles
        isFormulaRel = self.arcrole == "XBRL-formulae"  # all formula relationship arcroles
        isTableRenderingRel = self.arcrole == "Table-rendering"
        isFootnoteRel = self.arcrole == "XBRL-footnotes"  # all footnote relationship arcroles

        for modelLink in modelLinks:
            arcs = []
            linkEltQname = modelLink.qname
            for linkChild in modelLink:
                linkChildArcrole = linkChild.get(
                    "{http://www.w3.org/1999/xlink}arcrole")
                if linkChild.get("{http://www.w3.org/1999/xlink}type"
                                 ) == "arc" and linkChildArcrole:
                    linkChildQname = linkChild
                    if isFootnoteRel:
                        arcs.append(linkChild)
                    elif isDimensionRel:
                        if XbrlConst.isDimensionArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif isFormulaRel:
                        if XbrlConst.isFormulaArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif isTableRenderingRel:
                        if XbrlConst.isTableRenderingArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif arcrole == linkChildArcrole and \
                         (arcqname is None or arcqname == linkChildQname) and \
                         (linkqname is None or linkqname == linkEltQname):
                        arcs.append(linkChild)

            # build network
            for arcElement in arcs:
                arcrole = arcElement.get(
                    "{http://www.w3.org/1999/xlink}arcrole")
                fromLabel = arcElement.get(
                    "{http://www.w3.org/1999/xlink}from")
                toLabel = arcElement.get("{http://www.w3.org/1999/xlink}to")
                for fromResource in modelLink.labeledResources[fromLabel]:
                    for toResource in modelLink.labeledResources[toLabel]:
                        if isinstance(fromResource,
                                      ModelResource) and isinstance(
                                          toResource, ModelResource):
                            modelRel = ModelDtsObject.ModelRelationship(
                                modelLink.modelDocument, arcElement,
                                fromResource.dereference(),
                                toResource.dereference())
                            modelRelEquivalenceKey = modelRel.equivalenceKey  # this is a complex tuple to compute, get once for below
                            if modelRelEquivalenceKey not in relationships or \
                               modelRel.priorityOver(relationships[modelRelEquivalenceKey]):
                                relationships[
                                    modelRelEquivalenceKey] = modelRel

        #reduce effective arcs and order relationships...
        self.modelRelationshipsFrom = None
        self.modelRelationshipsTo = None
        self.modelConceptRoots = None
        self.modellinkRoleUris = None
        orderRels = defaultdict(list)
        for modelRel in relationships.values():
            if includeProhibits or not modelRel.isProhibited:
                orderRels[modelRel.order].append(modelRel)
        self.modelRelationships = [
            modelRel for order in sorted(orderRels.keys())
            for modelRel in orderRels[order]
        ]
        modelXbrl.relationshipSets[relationshipSetKey] = self
Ejemplo n.º 37
0
 def linkbaseDiscover(self, linkbaseElement, inInstance=False):
     for lbElement in linkbaseElement.iterchildren():
         if isinstance(lbElement, ModelObject):
             lbLn = lbElement.localName
             lbNs = lbElement.namespaceURI
             if lbNs == XbrlConst.link:
                 if lbLn == "roleRef" or lbLn == "arcroleRef":
                     href = self.discoverHref(lbElement)
                     if href is None:
                         self.modelXbrl.error(
                             "xmlSchema:requiredAttribute",
                             _("Linkbase reference for %(linkbaseRefElement)s href attribute missing or malformed"
                               ),
                             modelObject=lbElement,
                             linkbaseRefElement=lbLn)
                     else:
                         self.hrefObjects.append(href)
                     continue
             if lbElement.get(
                     "{http://www.w3.org/1999/xlink}type") == "extended":
                 if isinstance(lbElement, ModelLink):
                     self.schemalocateElementNamespace(lbElement)
                     arcrolesFound = set()
                     dimensionArcFound = False
                     formulaArcFound = False
                     tableRenderingArcFound = False
                     linkQn = qname(lbElement)
                     linkrole = lbElement.get(
                         "{http://www.w3.org/1999/xlink}role")
                     isStandardExtLink = XbrlConst.isStandardResourceOrExtLinkElement(
                         lbElement)
                     if inInstance:
                         #index footnote links even if no arc children
                         baseSetKeys = (("XBRL-footnotes", None, None,
                                         None), ("XBRL-footnotes", linkrole,
                                                 None, None))
                         for baseSetKey in baseSetKeys:
                             self.modelXbrl.baseSets[baseSetKey].append(
                                 lbElement)
                     for linkElement in lbElement.iterchildren():
                         if isinstance(linkElement, ModelObject):
                             self.schemalocateElementNamespace(linkElement)
                             xlinkType = linkElement.get(
                                 "{http://www.w3.org/1999/xlink}type")
                             modelResource = None
                             if xlinkType == "locator":
                                 nonDTS = linkElement.namespaceURI != XbrlConst.link or linkElement.localName != "loc"
                                 # only link:loc elements are discovered or processed
                                 href = self.discoverHref(linkElement,
                                                          nonDTS=nonDTS)
                                 if href is None:
                                     if isStandardExtLink:
                                         self.modelXbrl.error(
                                             "xmlSchema:requiredAttribute",
                                             _("Locator href attribute missing or malformed in standard extended link"
                                               ),
                                             modelObejct=linkElement)
                                     else:
                                         self.modelXbrl.warning(
                                             "arelle:hrefWarning",
                                             _("Locator href attribute missing or malformed in non-standard extended link"
                                               ),
                                             modelObejct=linkElement)
                                 else:
                                     linkElement.modelHref = href
                                     modelResource = linkElement
                             elif xlinkType == "arc":
                                 arcQn = qname(linkElement)
                                 arcrole = linkElement.get(
                                     "{http://www.w3.org/1999/xlink}arcrole"
                                 )
                                 if arcrole not in arcrolesFound:
                                     if linkrole == "":
                                         linkrole = XbrlConst.defaultLinkRole
                                     #index by both arcrole and linkrole#arcrole and dimensionsions if applicable
                                     baseSetKeys = [(arcrole, linkrole,
                                                     linkQn, arcQn)]
                                     baseSetKeys.append(
                                         (arcrole, linkrole, None, None))
                                     baseSetKeys.append(
                                         (arcrole, None, None, None))
                                     if XbrlConst.isDimensionArcrole(
                                             arcrole
                                     ) and not dimensionArcFound:
                                         baseSetKeys.append(
                                             ("XBRL-dimensions", None, None,
                                              None))
                                         baseSetKeys.append(
                                             ("XBRL-dimensions", linkrole,
                                              None, None))
                                         dimensionArcFound = True
                                     if XbrlConst.isFormulaArcrole(
                                             arcrole
                                     ) and not formulaArcFound:
                                         baseSetKeys.append(
                                             ("XBRL-formulae", None, None,
                                              None))
                                         baseSetKeys.append(
                                             ("XBRL-formulae", linkrole,
                                              None, None))
                                         formulaArcFound = True
                                     if XbrlConst.isTableRenderingArcrole(
                                             arcrole
                                     ) and not tableRenderingArcFound:
                                         baseSetKeys.append(
                                             ("Table-rendering", None, None,
                                              None))
                                         baseSetKeys.append(
                                             ("Table-rendering", linkrole,
                                              None, None))
                                         tableRenderingArcFound = True
                                         self.modelXbrl.hasTableRendering = True
                                     for baseSetKey in baseSetKeys:
                                         self.modelXbrl.baseSets[
                                             baseSetKey].append(lbElement)
                                     arcrolesFound.add(arcrole)
                             elif xlinkType == "resource":
                                 # create resource and make accessible by id for document
                                 modelResource = linkElement
                             if modelResource is not None:
                                 lbElement.labeledResources[linkElement.get("{http://www.w3.org/1999/xlink}label")] \
                                     .append(modelResource)
                 else:
                     self.modelXbrl.error(
                         "xbrl:schemaDefinitionMissing",
                         _("Linkbase extended link %(element)s missing schema definition"
                           ),
                         modelObject=lbElement,
                         element=lbElement.prefixedName)
Ejemplo n.º 38
0
 def isNumeric(self):
     try:
         return self._isNumeric
     except AttributeError:
         self._isNumeric = XbrlConst.isNumericXsdType(self.baseXsdType)
         return self._isNumeric
Ejemplo n.º 39
0
def init(modelXbrl):
    # setup modelXbrl for rendering evaluation

    # dimension defaults required in advance of validation
    from arelle import ValidateXbrlDimensions, ValidateFormula, ModelDocument
    ValidateXbrlDimensions.loadDimensionDefaults(modelXbrl)

    hasXbrlTables = False

    # validate table linkbase dimensions
    for baseSetKey in modelXbrl.baseSets.keys():
        arcrole, ELR, linkqname, arcqname = baseSetKey
        if ELR and linkqname and arcqname and XbrlConst.isTableRenderingArcrole(
                arcrole):
            ValidateFormula.checkBaseSet(
                modelXbrl, arcrole, ELR,
                modelXbrl.relationshipSet(arcrole, ELR, linkqname, arcqname))
            if arcrole in (XbrlConst.tableBreakdown,
                           XbrlConst.tableBreakdown201301,
                           XbrlConst.tableAxis2011):
                hasXbrlTables = True

    # provide context for view
    if modelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE:
        instance = None  # use instance of the entry pont
    else:  # need dummy instance
        instance = ModelDocument.create(
            modelXbrl,
            ModelDocument.Type.INSTANCE,
            "dummy.xml",  # fake URI and fake schemaRef 
            ("http://www.xbrl.org/2003/xbrl-instance-2003-12-31.xsd", ))

    if hasXbrlTables:
        # formula processor is needed for 2011 XBRL tables but not for 2010 Eurofiling tables
        modelXbrl.rendrCntx = XPathContext.create(modelXbrl, instance)

        modelXbrl.profileStat(None)

        # setup fresh parameters from formula optoins
        modelXbrl.parameters = modelXbrl.modelManager.formulaOptions.typedParameters(
        )

        # validate parameters and custom function signatures
        ValidateFormula.validate(modelXbrl,
                                 xpathContext=modelXbrl.rendrCntx,
                                 parametersOnly=True,
                                 statusMsg=_("compiling rendering tables"))

        # deprecated as of 2013-05-17
        # check and extract message expressions into compilable programs
        for msgArcrole in (XbrlConst.tableDefinitionNodeMessage201301,
                           XbrlConst.tableDefinitionNodeSelectionMessage201301,
                           XbrlConst.tableAxisMessage2011,
                           XbrlConst.tableAxisSelectionMessage2011):
            for msgRel in modelXbrl.relationshipSet(
                    msgArcrole).modelRelationships:
                ValidateFormula.checkMessageExpressions(
                    modelXbrl, msgRel.toModelObject)

        # compile and validate tables
        for modelTable in modelXbrl.modelRenderingTables:
            modelTable.fromInstanceQnames = None  # required if referred to by variables scope chaining
            modelTable.compile()

            # check aspectModel
            if modelTable.aspectModel not in ("non-dimensional",
                                              "dimensional"):
                modelXbrl.error(
                    "xbrlte:unknownAspectModel",
                    _("Table %(xlinkLabel)s, aspect model %(aspectModel)s not recognized"
                      ),
                    modelObject=modelTable,
                    xlinkLabel=modelTable.xlinkLabel,
                    aspectModel=modelTable.aspectModel)
            else:
                modelTable.priorAspectAxisDisposition = {}
                # check ordinate aspects against aspectModel
                oppositeAspectModel = (
                    _DICT_SET({'dimensional', 'non-dimensional'}) -
                    _DICT_SET({modelTable.aspectModel})).pop()
                uncoverableAspects = aspectModels[
                    oppositeAspectModel] - aspectModels[modelTable.aspectModel]
                for tblAxisRel in modelXbrl.relationshipSet(
                    (XbrlConst.tableBreakdown, XbrlConst.tableBreakdown201301,
                     XbrlConst.tableAxis2011)).fromModelObject(modelTable):
                    checkDefinitionNodeAspectModel(modelXbrl, modelTable,
                                                   tblAxisRel,
                                                   uncoverableAspects)
                del modelTable.priorAspectAxisDisposition

        modelXbrl.profileStat(_("compileTables"))
Ejemplo n.º 40
0
    def view(self, firstTime=False, relationshipSet=None):
        self.blockSelectEvent = 1
        self.blockViewModelObject = 0
        self.tag_has = defaultdict(list)  # temporary until Tk 8.6
        # relationship set based on linkrole parameter, to determine applicable linkroles
        if relationshipSet is None:
            relationshipSet = groupRelationshipSet(self.modelXbrl,
                                                   self.arcrole, self.linkrole,
                                                   self.linkqname,
                                                   self.arcqname)
        if not relationshipSet:
            self.modelXbrl.modelManager.addToLog(
                _("no relationships for {0}").format(
                    groupRelationshipLabel(self.arcrole)))
            return False

        if firstTime:
            self.showReferences = False
            # set up treeView widget and tabbed pane
            hdr = self.treeColHdr if self.treeColHdr else _(
                "{0} Relationships").format(
                    groupRelationshipLabel(self.arcrole))
            self.treeView.heading("#0", text=hdr)
            if self.isEbaTableIndex:
                # settings for the filing indicator column
                self.treeView.heading("#1", text='Filed')
                self.treeView.column("#1", width=40, anchor="w", stretch=False)
            if self.showColumns:
                if self.arcrole == XbrlConst.parentChild:  # extra columns
                    self.treeView.column("#0", width=300, anchor="w")
                    self.treeView["columns"] = ("preferredLabel", "type",
                                                "references")
                    self.treeView.column("preferredLabel",
                                         width=64,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("preferredLabel",
                                          text=_("Pref. Label"))
                    self.treeView.column("type",
                                         width=100,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("type", text=_("Type"))
                    self.treeView.column("references",
                                         width=200,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("references", text=_("References"))
                elif self.arcrole == XbrlConst.summationItem:  # extra columns
                    self.treeView.column("#0", width=300, anchor="w")
                    self.treeView["columns"] = ("weight", "balance")
                    self.treeView.column("weight",
                                         width=48,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("weight", text=_("Weight"))
                    self.treeView.column("balance",
                                         width=70,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("balance", text=_("Balance"))
                elif self.arcrole == "XBRL-dimensions":  # add columns for dimensional information
                    self.treeView.column("#0", width=300, anchor="w")
                    self.treeView["columns"] = ("arcrole", "contextElement",
                                                "closed", "usable")
                    self.treeView.column("arcrole",
                                         width=100,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("arcrole", text="Arcrole")
                    self.treeView.column("contextElement",
                                         width=50,
                                         anchor="center",
                                         stretch=False)
                    self.treeView.heading("contextElement", text="Context")
                    self.treeView.column("closed",
                                         width=40,
                                         anchor="center",
                                         stretch=False)
                    self.treeView.heading("closed", text="Closed")
                    self.treeView.column("usable",
                                         width=40,
                                         anchor="center",
                                         stretch=False)
                    self.treeView.heading("usable", text="Usable")
                elif self.arcrole == "Table-rendering":  # add columns for dimensional information
                    self.treeView.column("#0", width=160, anchor="w")
                    self.treeView["columns"] = ("axis", "abstract", "merge",
                                                "header", "priItem", "dims")
                    self.treeView.column("axis",
                                         width=28,
                                         anchor="center",
                                         stretch=False)
                    self.treeView.heading("axis", text="Axis")
                    self.treeView.column("abstract",
                                         width=24,
                                         anchor="center",
                                         stretch=False)
                    self.treeView.heading("abstract", text="Abs")
                    self.treeView.column("merge",
                                         width=26,
                                         anchor="center",
                                         stretch=False)
                    self.treeView.heading("merge", text="Mrg")
                    self.treeView.column("header",
                                         width=160,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("header", text="Header")
                    self.treeView.column("priItem",
                                         width=100,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("priItem", text="Primary Item")
                    self.treeView.column("dims",
                                         width=150,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("dims", text=_("Dimensions"))
                elif isinstance(self.arcrole,
                                (list, tuple)) or XbrlConst.isResourceArcrole(
                                    self.arcrole):
                    self.isResourceArcrole = True
                    self.showReferences = isinstance(
                        self.arcrole,
                        _STR_BASE) and self.arcrole.endswith("-reference")
                    self.treeView.column("#0", width=160, anchor="w")
                    self.treeView["columns"] = ("arcrole", "resource",
                                                "resourcerole", "lang")
                    self.treeView.column("arcrole",
                                         width=100,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("arcrole", text="Arcrole")
                    self.treeView.column("resource",
                                         width=60,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("resource", text="Resource")
                    self.treeView.column("resourcerole",
                                         width=100,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("resourcerole", text="Resource Role")
                    self.treeView.column("lang",
                                         width=36,
                                         anchor="w",
                                         stretch=False)
                    self.treeView.heading("lang", text="Lang")
        self.clearTreeView()
        self.id = 1

        # sort URIs by definition
        linkroleUris = []
        linkroleUriChildren = {}
        for linkroleUri in relationshipSet.linkRoleUris:
            modelRoleTypes = self.modelXbrl.roleTypes.get(linkroleUri)
            if modelRoleTypes:
                roledefinition = (
                    (self.hasTableIndex
                     and getattr(modelRoleTypes[0], "_tableIndex", False))
                    or modelRoleTypes[0].genLabel(lang=self.lang, strip=True)
                    or modelRoleTypes[0].definition or linkroleUri)
                roleId = modelRoleTypes[0].objectId(self.id)
                if (self.hasTableIndex
                        and getattr(modelRoleTypes[0], "_tableChildren")):
                    linkroleUriChildren[linkroleUri] = [
                        roleType.roleURI
                        for roleType in modelRoleTypes[0]._tableChildren
                    ]
            else:
                roledefinition = linkroleUri
                roleId = "node{0}".format(self.id)
            self.id += 1
            linkroleUris.append((roledefinition, linkroleUri, roleId))
        linkroleUris.sort()

        def insertLinkroleChildren(parentNode, childUris):
            for childUri in childUris:
                for roledefinition, linkroleUri, roleId in linkroleUris:
                    if childUri == linkroleUri and isinstance(
                            roledefinition, tuple):  # tableGroup
                        _nextTableGroup, _order, roledefinition = roledefinition
                        childId = "_{}{}".format(self.id, roleId)
                        self.id += 1
                        childNode = self.treeView.insert(parentNode,
                                                         "end",
                                                         childId,
                                                         text=roledefinition,
                                                         tags=("ELR", ))
                        if childUri in linkroleUriChildren:
                            insertLinkroleChildren(
                                childNode, linkroleUriChildren[childUri])
                        break

        # for each URI in definition order
        tableGroup = ""
        for roledefinition, linkroleUri, roleId in linkroleUris:
            if self.showLinkroles:
                if isinstance(roledefinition, tuple):  # tableGroup
                    nextTableGroup, _order, roledefinition = roledefinition
                    if tableGroup != nextTableGroup:
                        self.treeView.insert("",
                                             "end",
                                             nextTableGroup,
                                             text=nextTableGroup[1:],
                                             tags=("Group", ))
                        if not tableGroup:  # first tableGroup item, expand it
                            self.setTreeItemOpen(nextTableGroup, open=True)
                        tableGroup = nextTableGroup
                linknode = self.treeView.insert(tableGroup,
                                                "end",
                                                roleId,
                                                text=roledefinition,
                                                tags=("ELR", ))
                # add tableChildren as child nodes
                if linkroleUri in linkroleUriChildren:
                    insertLinkroleChildren(linknode,
                                           linkroleUriChildren[linkroleUri])
            else:
                linknode = ""
            if self.showRelationships:
                linkRelationshipSet = groupRelationshipSet(
                    self.modelXbrl, self.arcrole, linkroleUri, self.linkqname,
                    self.arcqname)
                for rootConcept in linkRelationshipSet.rootConcepts:
                    self.viewConcept(rootConcept, rootConcept, "",
                                     self.labelrole, linknode, 1,
                                     linkRelationshipSet, set())
                    self.tag_has[linkroleUri].append(linknode)

        if self.expandAllOnFirstDisplay:
            self.expandAll()
Ejemplo n.º 41
0
def checkDTSdocument(val, modelDocument, isFilingDocument):
    for hrefElt, _hrefedDoc, hrefId in modelDocument.hrefObjects:
        if hrefId:  #check scheme regardless of whether document loaded 
            # check all xpointer schemes
            for scheme, _path in XmlUtil.xpointerSchemes(hrefId):
                if scheme == "element" and val.validateDisclosureSystem:
                    val.modelXbrl.error(("EFM.6.03.06", "GFM.1.01.03"),
                        _("Href %(elementHref)s may only have shorthand xpointers"),
                        modelObject=hrefElt, 
                        elementHref=hrefElt.get("{http://www.w3.org/1999/xlink}href"))
    
    if not isFilingDocument:
        return  # not a filing's extension document
    
    if modelDocument.type == ModelDocument.Type.SCHEMA:
        if modelDocument.targetNamespace is not None and len(modelDocument.targetNamespace) > 85:
            l = len(modelDocument.targetNamespace.encode("utf-8"))
            if l > 255:
                val.modelXbrl.error("EFM.6.07.30",
                    _("Schema targetNamespace length (%(length)s) is over 255 bytes long in utf-8 %(targetNamespace)s"),
                    modelObject=modelDocument.xmlRootElement, length=l, targetNamespace=modelDocument.targetNamespace, value=modelDocument.targetNamespace)

    if modelDocument.type in (ModelDocument.Type.SCHEMA, ModelDocument.Type.LINKBASE):
        isSchema = modelDocument.type == ModelDocument.Type.SCHEMA
        if isSchema:
            for elt in modelDocument.xmlRootElement.iter(tag="{http://www.w3.org/2001/XMLSchema}*"):
                if elt.namespaceURI == XbrlConst.xsd:
                    localName = elt.localName
                    if localName in {"element", "complexType", "simpleType"}:
                        name = elt.get("name")
                        if name and len(name) > 64:
                            l = len(name.encode("utf-8"))
                            if l > 200:
                                val.modelXbrl.error("EFM.6.07.29",
                                    _("Schema %(element)s has a name length (%(length)s) over 200 bytes long in utf-8, %(name)s."),
                                    modelObject=elt, element=localName, name=name, length=l)
    
    for elt in modelDocument.xmlRootElement.iter():
        if isinstance(elt, ModelObject):
            xlinkType = elt.get("{http://www.w3.org/1999/xlink}type")
            xlinkRole = elt.get("{http://www.w3.org/1999/xlink}role")
            if elt.namespaceURI == XbrlConst.link:
                # check schema roleTypes        
                if elt.localName in ("roleType","arcroleType"):
                    uriAttr = {"roleType":"roleURI", "arcroleType":"arcroleURI"}[elt.localName]
                    roleURI = elt.get(uriAttr)
                    if len(roleURI) > 85:
                        l = len(roleURI.encode("utf-8"))
                        if l > 255:
                            val.modelXbrl.error("EFM.6.07.30",
                                _("Schema %(element)s %(attribute)s length (%(length)s) is over 255 bytes long in utf-8 %(roleURI)s"),
                                modelObject=elt, element=elt.qname, attribute=uriAttr, length=l, roleURI=roleURI, value=roleURI)
    
                if elt.localName == "arcroleRef":
                    refUri = elt.get("arcroleURI")
                    hrefAttr = elt.get("{http://www.w3.org/1999/xlink}href")
                    hrefUri, hrefId = UrlUtil.splitDecodeFragment(hrefAttr)
                    if hrefUri not in val.disclosureSystem.standardTaxonomiesDict:
                        val.modelXbrl.error(("EFM.6.09.06", "GFM.1.04.06"),
                            _("Arcrole %(refURI)s arcroleRef %(xlinkHref)s must be a standard taxonomy"),
                            modelObject=elt, refURI=refUri, xlinkHref=hrefUri)
            if modelDocument.type == ModelDocument.Type.INLINEXBRL and elt.namespaceURI in XbrlConst.ixbrlAll: 
                if elt.localName == "footnote":
                    if val.validateGFM:
                        if elt.get("{http://www.w3.org/1999/xlink}arcrole") != XbrlConst.factFootnote:
                            # must be in a nonDisplay div
                            if not any(inlineDisplayNonePattern.search(e.get("style") or "")
                                       for e in XmlUtil.ancestors(elt, XbrlConst.xhtml, "div")):
                                val.modelXbrl.error(("EFM.N/A", "GFM:1.10.16"),
                                    _("Inline XBRL footnote %(footnoteID)s must be in non-displayable div due to arcrole %(arcrole)s"),
                                    modelObject=elt, footnoteID=elt.get("footnoteID"), 
                                    arcrole=elt.get("{http://www.w3.org/1999/xlink}arcrole"))
                            
                        if not elt.get("{http://www.w3.org/XML/1998/namespace}lang"):
                            val.modelXbrl.error(("EFM.N/A", "GFM:1.10.13"),
                                _("Inline XBRL footnote %(footnoteID)s is missing an xml:lang attribute"),
                                modelObject=elt, footnoteID=id)
            if xlinkType == "extended":
                if not xlinkRole or xlinkRole == "":
                    val.modelXbrl.error(("EFM.6.09.04", "GFM.1.04.04"),
                        "%(element)s is missing an xlink:role",
                        modelObject=elt, element=elt.qname)
                if not val.extendedElementName:
                    val.extendedElementName = elt.qname
                elif val.extendedElementName != elt.qname:
                    val.modelXbrl.error(("EFM.6.09.07", "GFM:1.04.07"),
                        _("Extended element %(element)s must be the same as %(element2)s"),
                        modelObject=elt, element=elt.qname, element2=val.extendedElementName)
            elif xlinkType == "resource":
                if not xlinkRole:
                    val.modelXbrl.error(("EFM.6.09.04", "GFM.1.04.04"),
                        _("%(element)s is missing an xlink:role"),
                        modelObject=elt, element=elt.qname)
                elif not XbrlConst.isStandardRole(xlinkRole):
                    modelsRole = val.modelXbrl.roleTypes.get(xlinkRole)
                    if (modelsRole is None or len(modelsRole) == 0 or 
                        modelsRole[0].modelDocument.targetNamespace not in val.disclosureSystem.standardTaxonomiesDict):
                        val.modelXbrl.error(("EFM.6.09.05", "GFM.1.04.05"),
                            _("Resource %(xlinkLabel)s role %(role)s is not a standard taxonomy role"),
                            modelObject=elt, xlinkLabel=elt.get("{http://www.w3.org/1999/xlink}label"), role=xlinkRole, element=elt.qname,
                            roleDefinition=val.modelXbrl.roleTypeDefinition(xlinkRole))
            elif xlinkType == "arc":
                if elt.get("priority") is not None:
                    priority = elt.get("priority")
                    try:
                        if int(priority) >= 10:
                            val.modelXbrl.error(("EFM.6.09.09", "GFM.1.04.08"),
                                _("Arc from %(xlinkFrom)s to %(xlinkTo)s priority %(priority)s must be less than 10"),
                                modelObject=elt, 
                                arcElement=elt.qname,
                                xlinkFrom=elt.get("{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get("{http://www.w3.org/1999/xlink}to"),
                                priority=priority)
                    except (ValueError) :
                        val.modelXbrl.error(("EFM.6.09.09", "GFM.1.04.08"),
                            _("Arc from %(xlinkFrom)s to %(xlinkTo)s priority %(priority)s is not an integer"),
                            modelObject=elt, 
                            arcElement=elt.qname,
                            xlinkFrom=elt.get("{http://www.w3.org/1999/xlink}from"),
                            xlinkTo=elt.get("{http://www.w3.org/1999/xlink}to"),
                            priority=priority)
                if elt.namespaceURI == XbrlConst.link:
                    if elt.localName == "presentationArc" and not elt.get("order"):
                        val.modelXbrl.error(("EFM.6.12.01", "GFM.1.06.01"),
                            _("PresentationArc from %(xlinkFrom)s to %(xlinkTo)s must have an order"),
                            modelObject=elt, 
                            xlinkFrom=elt.get("{http://www.w3.org/1999/xlink}from"),
                            xlinkTo=elt.get("{http://www.w3.org/1999/xlink}to"),
                            conceptFrom=arcFromConceptQname(elt),
                            conceptTo=arcToConceptQname(elt))
                    elif elt.localName == "calculationArc":
                        if not elt.get("order"):
                            val.modelXbrl.error(("EFM.6.14.01", "GFM.1.07.01"),
                                _("CalculationArc from %(xlinkFrom)s to %(xlinkTo)s must have an order"),
                                modelObject=elt, 
                                xlinkFrom=elt.get("{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get("{http://www.w3.org/1999/xlink}to"),
                                conceptFrom=arcFromConceptQname(elt),
                                conceptTo=arcToConceptQname(elt))
                        try:
                            weightAttr = elt.get("weight")
                            weight = float(weightAttr)
                            if not weight in (1, -1):
                                val.modelXbrl.error(("EFM.6.14.02", "GFM.1.07.02"),
                                    _("CalculationArc from %(xlinkFrom)s to %(xlinkTo)s weight %(weight)s must be 1 or -1"),
                                    modelObject=elt, 
                                    xlinkFrom=elt.get("{http://www.w3.org/1999/xlink}from"),
                                    xlinkTo=elt.get("{http://www.w3.org/1999/xlink}to"),
                                    conceptFrom=arcFromConceptQname(elt),
                                    conceptTo=arcToConceptQname(elt),
                                    weight=weightAttr)
                        except ValueError:
                            val.modelXbrl.error(("EFM.6.14.02", "GFM.1.07.02"),
                                _("CalculationArc from %(xlinkFrom)s to %(xlinkTo)s must have an weight (value error in \"%(weight)s\")"),
                                modelObject=elt, 
                                xlinkFrom=elt.get("{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get("{http://www.w3.org/1999/xlink}to"),
                                conceptFrom=arcFromConceptQname(elt),
                                conceptTo=arcToConceptQname(elt),
                                weight=weightAttr)
                    elif elt.localName == "definitionArc":
                        if not elt.get("order"):
                            val.modelXbrl.error(("EFM.6.16.01", "GFM.1.08.01"),
                                _("DefinitionArc from %(xlinkFrom)s to %(xlinkTo)s must have an order"),
                                modelObject=elt, 
                                xlinkFrom=elt.get("{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get("{http://www.w3.org/1999/xlink}to"),
                                conceptFrom=arcFromConceptQname(elt),
                                conceptTo=arcToConceptQname(elt))
Ejemplo n.º 42
0
 def linkbaseDiscover(self, linkbaseElement, inInstance=False):
     for lbElement in linkbaseElement.childNodes:
         if lbElement.nodeType == 1:  #element
             lbLn = lbElement.localName
             lbNs = lbElement.namespaceURI
             if lbNs == XbrlConst.link:
                 if lbLn == "roleRef" or lbLn == "arcroleRef":
                     href = self.discoverHref(lbElement)
                     if href is None:
                         self.modelXbrl.error(
                             "Linkbase in {0} {1} href attribute missing or malformed"
                             .format(os.path.basename(self.uri),
                                     lbLn), "err", "xbrl:hrefMissing")
                     else:
                         self.hrefObjects.append(href)
                     continue
             if lbElement.getAttributeNS(XbrlConst.xlink,
                                         "type") == "extended":
                 self.schemalocateElementNamespace(lbElement)
                 arcrolesFound = set()
                 dimensionArcFound = False
                 formulaArcFound = False
                 euRenderingArcFound = False
                 linkQn = qname(lbElement)
                 linkrole = lbElement.getAttributeNS(
                     XbrlConst.xlink, "role")
                 modelLink = ModelObject.createLink(self, lbElement)
                 if inInstance:
                     #index footnote links even if no arc children
                     baseSetKeys = (("XBRL-footnotes", None, None, None),
                                    ("XBRL-footnotes", linkrole, None,
                                     None))
                     for baseSetKey in baseSetKeys:
                         self.modelXbrl.baseSets[baseSetKey].append(
                             modelLink)
                 for linkElement in lbElement.childNodes:
                     if linkElement.nodeType == 1:  #element
                         self.schemalocateElementNamespace(linkElement)
                         xlinkType = linkElement.getAttributeNS(
                             XbrlConst.xlink, "type")
                         modelResource = None
                         if xlinkType == "locator":
                             nonDTS = linkElement.namespaceURI != XbrlConst.link or linkElement.localName != "loc"
                             # only link:loc elements are discovered or processed
                             href = self.discoverHref(linkElement,
                                                      nonDTS=nonDTS)
                             if href is None:
                                 self.modelXbrl.error(
                                     "Linkbase in {0} {1} href attribute missing or malformed"
                                     .format(os.path.basename(self.uri),
                                             lbLn), "err",
                                     "xbrl:hrefMissing")
                             else:
                                 modelResource = ModelObject.createLocator(
                                     self, linkElement, href)
                         elif xlinkType == "arc":
                             arcQn = qname(linkElement)
                             arcrole = linkElement.getAttributeNS(
                                 XbrlConst.xlink, "arcrole")
                             if arcrole not in arcrolesFound:
                                 if linkrole == "":
                                     linkrole = XbrlConst.defaultLinkRole
                                 #index by both arcrole and linkrole#arcrole and dimensionsions if applicable
                                 baseSetKeys = [(arcrole, linkrole, linkQn,
                                                 arcQn)]
                                 baseSetKeys.append(
                                     (arcrole, linkrole, None, None))
                                 baseSetKeys.append(
                                     (arcrole, None, None, None))
                                 if XbrlConst.isDimensionArcrole(
                                         arcrole) and not dimensionArcFound:
                                     baseSetKeys.append(("XBRL-dimensions",
                                                         None, None, None))
                                     baseSetKeys.append(
                                         ("XBRL-dimensions", linkrole, None,
                                          None))
                                     dimensionArcFound = True
                                 if XbrlConst.isFormulaArcrole(
                                         arcrole) and not formulaArcFound:
                                     baseSetKeys.append(("XBRL-formulae",
                                                         None, None, None))
                                     baseSetKeys.append(
                                         ("XBRL-formulae", linkrole, None,
                                          None))
                                     formulaArcFound = True
                                 if XbrlConst.isEuRenderingArcrole(
                                         arcrole
                                 ) and not euRenderingArcFound:
                                     baseSetKeys.append(
                                         ("EU-rendering", None, None, None))
                                     baseSetKeys.append(
                                         ("EU-rendering", linkrole, None,
                                          None))
                                     euRenderingArcFound = True
                                     self.modelXbrl.hasEuRendering = True
                                 for baseSetKey in baseSetKeys:
                                     self.modelXbrl.baseSets[
                                         baseSetKey].append(modelLink)
                                 arcrolesFound.add(arcrole)
                         elif xlinkType == "resource":
                             # create resource and make accessible by id for document
                             modelResource = ModelObject.createResource(
                                 self, linkElement)
                         if modelResource is not None:
                             if linkElement.hasAttribute("id"):
                                 self.idObjects[linkElement.getAttribute(
                                     "id")] = modelResource
                             modelLink.labeledResources[linkElement.getAttributeNS(XbrlConst.xlink, "label")] \
                                 .append(modelResource)
                         else:
                             XmlUtil.markIdAttributes(linkElement)
Ejemplo n.º 43
0
    def view(self, firstTime=False, relationshipSet=None):
        self.blockSelectEvent = 1
        self.blockViewModelObject = 0
        self.tag_has = defaultdict(list) # temporary until Tk 8.6
        # relationship set based on linkrole parameter, to determine applicable linkroles
        if relationshipSet is None:
            relationshipSet = groupRelationshipSet(self.modelXbrl, self.arcrole, self.linkrole, self.linkqname, self.arcqname)
        if not relationshipSet:
            self.modelXbrl.modelManager.addToLog(_("no relationships for {0}").format(groupRelationshipLabel(self.arcrole)))
            return False
        
        if firstTime:
            self.showReferences = False
            # set up treeView widget and tabbed pane
            hdr = self.treeColHdr if self.treeColHdr else _("{0} Relationships").format(groupRelationshipLabel(self.arcrole))
            self.treeView.heading("#0", text=hdr)
            if self.showColumns:
                if self.arcrole == XbrlConst.parentChild: # extra columns
                    self.treeView.column("#0", width=300, anchor="w")
                    self.treeView["columns"] = ("preferredLabel", "type", "references")
                    self.treeView.column("preferredLabel", width=64, anchor="w", stretch=False)
                    self.treeView.heading("preferredLabel", text=_("Pref. Label"))
                    self.treeView.column("type", width=100, anchor="w", stretch=False)
                    self.treeView.heading("type", text=_("Type"))
                    self.treeView.column("references", width=200, anchor="w", stretch=False)
                    self.treeView.heading("references", text=_("References"))
                elif self.arcrole == XbrlConst.summationItem: # extra columns
                    self.treeView.column("#0", width=300, anchor="w")
                    self.treeView["columns"] = ("weight", "balance")
                    self.treeView.column("weight", width=48, anchor="w", stretch=False)
                    self.treeView.heading("weight", text=_("Weight"))
                    self.treeView.column("balance", width=70, anchor="w", stretch=False)
                    self.treeView.heading("balance", text=_("Balance"))
                elif self.arcrole == "XBRL-dimensions":    # add columns for dimensional information
                    self.treeView.column("#0", width=300, anchor="w")
                    self.treeView["columns"] = ("arcrole", "contextElement", "closed", "usable")
                    self.treeView.column("arcrole", width=100, anchor="w", stretch=False)
                    self.treeView.heading("arcrole", text="Arcrole")
                    self.treeView.column("contextElement", width=50, anchor="center", stretch=False)
                    self.treeView.heading("contextElement", text="Context")
                    self.treeView.column("closed", width=40, anchor="center", stretch=False)
                    self.treeView.heading("closed", text="Closed")
                    self.treeView.column("usable", width=40, anchor="center", stretch=False)
                    self.treeView.heading("usable", text="Usable")
                elif self.arcrole == "Table-rendering":    # add columns for dimensional information
                    self.treeView.column("#0", width=160, anchor="w")
                    self.treeView["columns"] = ("axis", "abstract", "merge", "header", "priItem", "dims")
                    self.treeView.column("axis", width=28, anchor="center", stretch=False)
                    self.treeView.heading("axis", text="Axis")
                    self.treeView.column("abstract", width=24, anchor="center", stretch=False)
                    self.treeView.heading("abstract", text="Abs")
                    self.treeView.column("merge", width=26, anchor="center", stretch=False)
                    self.treeView.heading("merge", text="Mrg")
                    self.treeView.column("header", width=160, anchor="w", stretch=False)
                    self.treeView.heading("header", text="Header")
                    self.treeView.column("priItem", width=100, anchor="w", stretch=False)
                    self.treeView.heading("priItem", text="Primary Item")
                    self.treeView.column("dims", width=150, anchor="w", stretch=False)
                    self.treeView.heading("dims", text=_("Dimensions"))
                elif isinstance(self.arcrole, (list,tuple)) or XbrlConst.isResourceArcrole(self.arcrole):
                    self.isResourceArcrole = True
                    self.showReferences = isinstance(self.arcrole, _STR_BASE) and self.arcrole.endswith("-reference")
                    self.treeView.column("#0", width=160, anchor="w")
                    self.treeView["columns"] = ("arcrole", "resource", "resourcerole", "lang")
                    self.treeView.column("arcrole", width=100, anchor="w", stretch=False)
                    self.treeView.heading("arcrole", text="Arcrole")
                    self.treeView.column("resource", width=60, anchor="w", stretch=False)
                    self.treeView.heading("resource", text="Resource")
                    self.treeView.column("resourcerole", width=100, anchor="w", stretch=False)
                    self.treeView.heading("resourcerole", text="Resource Role")
                    self.treeView.column("lang", width=36, anchor="w", stretch=False)
                    self.treeView.heading("lang", text="Lang")
        self.id = 1
        for previousNode in self.treeView.get_children(""): 
            self.treeView.delete(previousNode)
        # sort URIs by definition
        linkroleUris = []
        for linkroleUri in relationshipSet.linkRoleUris:
            modelRoleTypes = self.modelXbrl.roleTypes.get(linkroleUri)
            if modelRoleTypes:
                roledefinition = (modelRoleTypes[0].genLabel(lang=self.lang, strip=True) or modelRoleTypes[0].definition or linkroleUri)
                roleId = modelRoleTypes[0].objectId(self.id)
            else:
                roledefinition = linkroleUri
                roleId = "node{0}".format(self.id)
            self.id += 1
            linkroleUris.append((roledefinition, linkroleUri, roleId))
        linkroleUris.sort()
        # for each URI in definition order
        for roledefinition, linkroleUri, roleId in linkroleUris:
            if self.showLinkroles:
                linknode = self.treeView.insert("", "end", roleId, text=roledefinition, tags=("ELR",))
            else:
                linknode = ""
            if self.showRelationships:
                linkRelationshipSet = groupRelationshipSet(self.modelXbrl, self.arcrole, linkroleUri, self.linkqname, self.arcqname)
                for rootConcept in linkRelationshipSet.rootConcepts:
                    self.viewConcept(rootConcept, rootConcept, "", self.labelrole, linknode, 1, linkRelationshipSet, set())
                    self.tag_has[linkroleUri].append(linknode)

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

        modelXbrl.dimensionDefaultConcepts = {}
        modelXbrl.qnameDimensionDefaults = {}
        modelXbrl.qnameDimensionContextElement = {}
        # check base set cycles, dimensions
        modelXbrl.modelManager.showStatus(_("validating relationship sets"))
        for baseSetKey in modelXbrl.baseSets.keys():
            arcrole, ELR, linkqname, arcqname = baseSetKey
            if arcrole.startswith("XBRL-") or ELR is None or \
                linkqname is None or arcqname is None:
                continue
            elif arcrole in XbrlConst.standardArcroleCyclesAllowed:
                # TODO: table should be in this module, where it is used
                cyclesAllowed, specSect = XbrlConst.standardArcroleCyclesAllowed[arcrole]
            elif arcrole in self.modelXbrl.arcroleTypes and len(self.modelXbrl.arcroleTypes[arcrole]) > 0:
                cyclesAllowed = self.modelXbrl.arcroleTypes[arcrole][0].cyclesAllowed
                if arcrole in self.genericArcArcroles:
                    specSect = "xbrlgene:violatedCyclesConstraint"
                else:
                    specSect = "xbrl.5.1.4.3:cycles"
            else:
                cyclesAllowed = "any"
                specSect = None
            if cyclesAllowed != "any" or arcrole in (XbrlConst.summationItem,) \
                                      or arcrole in self.genericArcArcroles  \
                                      or arcrole.startswith(XbrlConst.formulaStartsWith):
                relsSet = modelXbrl.relationshipSet(arcrole,ELR,linkqname,arcqname)
            if cyclesAllowed != "any" and \
                   (XbrlConst.isStandardExtLinkQname(linkqname) and XbrlConst.isStandardArcQname(arcqname)) \
                   or arcrole in self.genericArcArcroles:
                noUndirected = cyclesAllowed == "none"
                fromRelationships = relsSet.fromModelObjects()
                for relFrom, rels in fromRelationships.items():
                    cycleFound = self.fwdCycle(relsSet, rels, noUndirected, {relFrom})
                    if cycleFound is not None:
                        path = str(relFrom.qname) + " " + " - ".join(
                            "{0}:{1} {2}".format(rel.modelDocument.basename, rel.sourceline, rel.toModelObject.qname)
                            for rel in reversed(cycleFound[1:]))
                        modelXbrl.error(specSect,
                            _("Relationships have a %(cycle)s cycle in arcrole %(arcrole)s \nlink role %(linkrole)s \nlink %(linkname)s, \narc %(arcname)s, \npath %(path)s"),
                            modelObject=cycleFound[1:], cycle=cycleFound[0], path=path,
                            arcrole=arcrole, linkrole=ELR, linkname=linkqname, arcname=arcqname), 
                        break
                
            # check calculation arcs for weight issues (note calc arc is an "any" cycles)
            if arcrole == XbrlConst.summationItem:
                for modelRel in relsSet.modelRelationships:
                    weight = modelRel.weight
                    fromConcept = modelRel.fromModelObject
                    toConcept = modelRel.toModelObject
                    if fromConcept is not None and toConcept is not None:
                        if weight == 0:
                            modelXbrl.error("xbrl.5.2.5.2.1:zeroWeight",
                                _("Calculation relationship has zero weight from %(source)s to %(target)s in link role %(linkrole)s"),
                                modelObject=modelRel,
                                source=fromConcept.qname, target=toConcept.qname, linkrole=ELR), 
                        fromBalance = fromConcept.balance
                        toBalance = toConcept.balance
                        if fromBalance and toBalance:
                            if (fromBalance == toBalance and weight < 0) or \
                               (fromBalance != toBalance and weight > 0):
                                modelXbrl.error("xbrl.5.1.1.2:balanceCalcWeightIllegal" +
                                                ("Negative" if weight < 0 else "Positive"),
                                    _("Calculation relationship has illegal weight %(weight)s from %(source)s, %(sourceBalance)s, to %(target)s, %(targetBalance)s, in link role %(linkrole)s (per 5.1.1.2 Table 6)"),
                                    modelObject=modelRel, weight=weight,
                                    source=fromConcept.qname, target=toConcept.qname, linkrole=ELR, 
                                    sourceBalance=fromBalance, targetBalance=toBalance)
                        if not fromConcept.isNumeric or not toConcept.isNumeric:
                            modelXbrl.error("xbrl.5.2.5.2:nonNumericCalc",
                                _("Calculation relationship has illegal concept from %(source)s%(sourceNumericDecorator)s to %(target)s%(targetNumericDecorator)s in link role %(linkrole)s"),
                                modelObject=modelRel,
                                source=fromConcept.qname, target=toConcept.qname, linkrole=ELR, 
                                sourceNumericDecorator="" if fromConcept.isNumeric else _(" (non-numeric)"), 
                                targetNumericDecorator="" if toConcept.isNumeric else _(" (non-numeric)"))
            # check presentation relationships for preferredLabel issues
            elif arcrole == XbrlConst.parentChild:
                for modelRel in relsSet.modelRelationships:
                    preferredLabel = modelRel.preferredLabel
                    toConcept = modelRel.toModelObject
                    if preferredLabel is not None and toConcept is not None and \
                       toConcept.label(preferredLabel=preferredLabel,fallbackToQname=False) is None:
                        modelXbrl.error("xbrl.5.2.4.2.1:preferredLabelMissing",
                            _("Presentation relationship from %(source)s to %(target)s in link role %(linkrole)s missing preferredLabel %(preferredLabel)s"),
                            modelObject=modelRel,
                            source=modelRel.fromModelObject.qname, target=toConcept.qname, linkrole=ELR, 
                            preferredLabel=preferredLabel)
            # check essence-alias relationships
            elif arcrole == XbrlConst.essenceAlias:
                for modelRel in relsSet.modelRelationships:
                    fromConcept = modelRel.fromModelObject
                    toConcept = modelRel.toModelObject
                    if fromConcept is not None and toConcept is not None:
                        if fromConcept.type != toConcept.type or fromConcept.periodType != toConcept.periodType:
                            modelXbrl.error("xbrl.5.2.6.2.2:essenceAliasTypes",
                                _("Essence-alias relationship from %(source)s to %(target)s in link role %(linkrole)s has different types or periodTypes"),
                                modelObject=modelRel,
                                source=fromConcept.qname, target=toConcept.qname, linkrole=ELR)
                        fromBalance = fromConcept.balance
                        toBalance = toConcept.balance
                        if fromBalance and toBalance:
                            if fromBalance and toBalance and fromBalance != toBalance:
                                modelXbrl.error("xbrl.5.2.6.2.2:essenceAliasBalance",
                                    _("Essence-alias relationship from %(source)s to %(target)s in link role %(linkrole)s has different balances")).format(
                                    modelObject=modelRel,
                                    source=fromConcept.qname, target=toConcept.qname, linkrole=ELR)
            elif modelXbrl.hasXDT and arcrole.startswith(XbrlConst.dimStartsWith):
                ValidateXbrlDimensions.checkBaseSet(self, arcrole, ELR, relsSet)             
            elif (modelXbrl.hasFormulae or modelXbrl.hasTableRendering) and arcrole.startswith(XbrlConst.formulaStartsWith):
                ValidateFormula.checkBaseSet(self, arcrole, ELR, relsSet)
        modelXbrl.isDimensionsValidated = True
        modelXbrl.profileStat(_("validateRelationships"))
                            
        # instance checks
        modelXbrl.modelManager.showStatus(_("validating instance"))
        self.footnoteRefs = set()
        if modelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE or \
           modelXbrl.modelDocument.type == ModelDocument.Type.INLINEXBRL:
            self.factsWithDeprecatedIxNamespace = []
            self.checkFacts(modelXbrl.facts)
            
            if self.factsWithDeprecatedIxNamespace:
                self.modelXbrl.info("arelle:info",
                    _("%(count)s facts have deprecated transformation namespace %(namespace)s"),
                        modelObject=self.factsWithDeprecatedIxNamespace,
                        count=len(self.factsWithDeprecatedIxNamespace), 
                        namespace=FunctionIxt.deprecatedNamespaceURI)
            del self.factsWithDeprecatedIxNamespace

            
            #instance checks
            for cntx in modelXbrl.contexts.values():
                if cntx.isStartEndPeriod:
                    try:
                        if cntx.endDatetime <= cntx.startDatetime:
                            self.modelXbrl.error("xbrl.4.7.2:periodStartBeforeEnd",
                                _("Context %(contextID)s must have startDate less than endDate"),
                                modelObject=cntx, contextID=cntx.id)
                    except (TypeError, ValueError) as err:
                        self.modelXbrl.error("xbrl.4.7.2:contextDateError",
                            _("Context %(contextID) startDate or endDate: %(error)s"),
                            modelObject=cntx, contextID=cntx.id, error=err)
                elif cntx.isInstantPeriod:
                    try:
                        cntx.instantDatetime #parse field
                    except ValueError as err:
                        self.modelXbrl.error("xbrl.4.7.2:contextDateError",
                            _("Context %(contextID)s instant date: %(error)s"),
                            modelObject=cntx, contextID=cntx.id, error=err)
                self.segmentScenario(cntx.segment, cntx.id, "segment", "4.7.3.2")
                self.segmentScenario(cntx.scenario, cntx.id, "scenario", "4.7.4")
                
            for unit in modelXbrl.units.values():
                mulDivMeasures = unit.measures
                if mulDivMeasures:
                    for measures in mulDivMeasures:
                        for measure in measures:
                            if measure.namespaceURI == XbrlConst.xbrli and not \
                                measure in (XbrlConst.qnXbrliPure, XbrlConst.qnXbrliShares):
                                    self.modelXbrl.error("xbrl.4.8.2:measureElement",
                                        _("Unit %(unitID)s illegal measure: %(measure)s"),
                                        modelObject=unit, unitID=unit.id, measure=measure)
                    for numeratorMeasure in mulDivMeasures[0]:
                        if numeratorMeasure in mulDivMeasures[1]:
                            self.modelXbrl.error("xbrl.4.8.4:measureBothNumDenom",
                                _("Unit %(unitID)s numerator measure: %(measure)s also appears as denominator measure"),
                                modelObject=unit, unitID=unit.id, measure=numeratorMeasure)
            modelXbrl.profileStat(_("validateInstance"))

            if modelXbrl.hasXDT:            
                modelXbrl.modelManager.showStatus(_("validating dimensions"))
                ''' uncomment if using otherFacts in checkFact
                dimCheckableFacts = set(f 
                                        for f in modelXbrl.factsInInstance
                                        if f.concept.isItem and f.context is not None)
                while (dimCheckableFacts): # check one and all of its compatible family members
                    f = dimCheckableFacts.pop()
                    ValidateXbrlDimensions.checkFact(self, f, dimCheckableFacts)
                del dimCheckableFacts
                '''
                self.checkFactDimensions(modelXbrl.facts) # check fact dimensions in document order
                for cntx in modelXbrl.contexts.values():
                    ValidateXbrlDimensions.checkContext(self,cntx)
                modelXbrl.profileStat(_("validateDimensions"))
                    
        # dimensional validity
        #concepts checks
        modelXbrl.modelManager.showStatus(_("validating concepts"))
        for concept in modelXbrl.qnameConcepts.values():
            conceptType = concept.type
            if XbrlConst.isStandardNamespace(concept.qname.namespaceURI) or \
               not concept.modelDocument.inDTS:
                continue
            
            if concept.isTuple:
                # must be global
                if not concept.getparent().localName == "schema":
                    self.modelXbrl.error("xbrl.4.9:tupleGloballyDeclared",
                        _("Tuple %(concept)s must be declared globally"),
                        modelObject=concept, concept=concept.qname)
                if concept.periodType:
                    self.modelXbrl.error("xbrl.4.9:tuplePeriodType",
                        _("Tuple %(concept)s must not have periodType"),
                        modelObject=concept, concept=concept.qname)
                if concept.balance:
                    self.modelXbrl.error("xbrl.4.9:tupleBalance",
                        _("Tuple %(concept)s must not have balance"),
                        modelObject=concept, concept=concept.qname)
                if conceptType is not None:
                    # check attribute declarations
                    for attribute in conceptType.attributes.values():
                        if attribute.qname.namespaceURI in (XbrlConst.xbrli, XbrlConst.link, XbrlConst.xlink, XbrlConst.xl):
                            self.modelXbrl.error("xbrl.4.9:tupleAttribute",
                                _("Tuple %(concept)s must not have attribute in this namespace %(attribute)s"),
                                modelObject=concept, concept=concept.qname, attribute=attribute.qname)
                    # check for mixed="true" or simple content
                    if XmlUtil.descendantAttr(conceptType, XbrlConst.xsd, ("complexType", "complexContent"), "mixed") == "true":
                        self.modelXbrl.error("xbrl.4.9:tupleMixedContent",
                            _("Tuple %(concept)s must not have mixed content"),
                            modelObject=concept, concept=concept.qname)
                    if XmlUtil.descendant(conceptType, XbrlConst.xsd, "simpleContent"):
                        self.modelXbrl.error("xbrl.4.9:tupleSimpleContent",
                            _("Tuple %(concept)s must not have simple content"),
                            modelObject=concept, concept=concept.qname)
                    # child elements must be item or tuple
                    for elementQname in conceptType.elements:
                        childConcept = self.modelXbrl.qnameConcepts.get(elementQname)
                        if childConcept is None:
                            self.modelXbrl.error("xbrl.4.9:tupleElementUndefined",
                                _("Tuple %(concept)s element %(tupleElement)s not defined"),
                                modelObject=concept, concept=str(concept.qname), tupleElement=elementQname)
                        elif not (childConcept.isItem or childConcept.isTuple or # isItem/isTuple do not include item or tuple itself
                                  childConcept.qname == XbrlConst.qnXbrliItem or # subs group includes item as member
                                  childConcept.qname == XbrlConst.qnXbrliTuple):
                            self.modelXbrl.error("xbrl.4.9:tupleElementItemOrTuple",
                                _("Tuple %(concept)s must not have element %(tupleElement)s not an item or tuple"),
                                modelObject=concept, concept=concept.qname, tupleElement=elementQname)
            elif concept.isItem:
                if concept.periodType not in periodTypeValues: #("instant","duration"):
                    self.modelXbrl.error("xbrl.5.1.1.1:itemPeriodType",
                        _("Item %(concept)s must have a valid periodType"),
                        modelObject=concept, concept=concept.qname)
                if concept.isMonetary:
                    if concept.balance not in balanceValues: #(None, "credit","debit"):
                        self.modelXbrl.error("xbrl.5.1.1.2:itemBalance",
                            _("Item %(concept)s must have a valid balance %(balance)s"),
                            modelObject=concept, concept=concept.qname, balance=concept.balance)
                else:
                    if concept.balance:
                        self.modelXbrl.error("xbrl.5.1.1.2:itemBalance",
                            _("Item %(concept)s may not have a balance"),
                            modelObject=concept, concept=concept.qname)
                if concept.baseXbrliType not in baseXbrliTypes:
                    self.modelXbrl.error("xbrl.5.1.1.3:itemType",
                        _("Item %(concept)s type %(itemType)s invalid"),
                        modelObject=concept, concept=concept.qname, itemType=concept.baseXbrliType)
                if modelXbrl.hasXDT:
                    if concept.isHypercubeItem and not concept.abstract == "true":
                        self.modelXbrl.error("xbrldte:HypercubeElementIsNotAbstractError",
                            _("Hypercube item %(concept)s must be abstract"),
                            modelObject=concept, concept=concept.qname)
                    elif concept.isDimensionItem and not concept.abstract == "true":
                        self.modelXbrl.error("xbrldte:DimensionElementIsNotAbstractError",
                            _("Dimension item %(concept)s must be abstract"),
                            modelObject=concept, concept=concept.qname)
            if modelXbrl.hasXDT:
                ValidateXbrlDimensions.checkConcept(self, concept)
        modelXbrl.profileStat(_("validateConcepts"))
            
        modelXbrl.modelManager.showStatus(_("validating DTS"))
        self.DTSreferenceResourceIDs = {}
        ValidateXbrlDTS.checkDTS(self, modelXbrl.modelDocument, [])
        del self.DTSreferenceResourceIDs
        
        global validateUniqueParticleAttribution
        if validateUniqueParticleAttribution is None:
            from arelle.XmlValidateParticles import validateUniqueParticleAttribution
        for modelType in modelXbrl.qnameTypes.values():
            validateUniqueParticleAttribution(modelXbrl, modelType.particlesList, modelType)
        modelXbrl.profileStat(_("validateDTS"))
        
        if self.validateCalcLB:
            modelXbrl.modelManager.showStatus(_("Validating instance calculations"))
            ValidateXbrlCalcs.validate(modelXbrl, inferDecimals=self.validateInferDecimals)
            modelXbrl.profileStat(_("validateCalculations"))
            
        if (modelXbrl.modelManager.validateUtr or
            (self.parameters and self.parameters.get(qname("forceUtrValidation",noPrefixIsNoNamespace=True),(None,"false"))[1] == "true") or
             #(self.validateEFM and 
             #any((concept.namespaceURI in self.disclosureSystem.standardTaxonomiesDict) 
             #    for concept in self.modelXbrl.nameConcepts.get("UTR",())))):
            (self.validateEFM and any(modelDoc.definesUTR for modelDoc in self.modelXbrl.urlDocs.values()))):
            ValidateUtr.validate(modelXbrl)
            modelXbrl.profileStat(_("validateUTR"))
            
        if modelXbrl.hasFormulae or modelXbrl.modelRenderingTables:
            ValidateFormula.validate(self, 
                                     statusMsg=_("compiling formulae and rendering tables") if (modelXbrl.hasFormulae and modelXbrl.modelRenderingTables)
                                     else (_("compiling formulae") if modelXbrl.hasFormulae
                                           else _("compiling rendering tables")))
            
        modelXbrl.modelManager.showStatus(_("ready"), 2000)
Ejemplo n.º 46
0
    def __init__(self,
                 modelXbrl,
                 arcrole,
                 linkrole=None,
                 linkqname=None,
                 arcqname=None,
                 includeProhibits=False):
        self.isChanged = False
        self.modelXbrl = modelXbrl
        self.arcrole = arcrole  # may be str, tuple or frozenset
        self.linkrole = linkrole  # may be str, tuple or frozenset
        self.linkqname = linkqname
        self.arcqname = arcqname

        relationshipSetKey = (arcrole, linkrole, linkqname, arcqname,
                              includeProhibits)

        # base sets does not care about the #includeProhibits
        if isinstance(arcrole,
                      (str, NoneType)) and isinstance(linkrole,
                                                      (str, NoneType)):
            modelLinks = self.modelXbrl.baseSets.get(
                (arcrole, linkrole, linkqname, arcqname), [])
        else:  # arcrole is a set of arcroles
            modelLinks = []
            for ar in (arcrole, ) if isinstance(arcrole,
                                                (str, NoneType)) else arcrole:
                for lr in (linkrole, ) if isinstance(linkrole,
                                                     (str,
                                                      NoneType)) else linkrole:
                    modelLinks.extend(
                        self.modelXbrl.baseSets.get(
                            (ar, lr, linkqname, arcqname), []))

        # gather arcs
        relationships = {}
        isDimensionRel = self.arcrole == "XBRL-dimensions"  # all dimensional relationship arcroles
        isFormulaRel = self.arcrole == "XBRL-formulae"  # all formula relationship arcroles
        isTableRenderingRel = self.arcrole == "Table-rendering"
        isFootnoteRel = self.arcrole == "XBRL-footnotes"  # all footnote relationship arcroles
        if not isinstance(arcrole, (tuple, frozenset)):
            arcrole = (arcrole, )

        for modelLink in modelLinks:
            arcs = []
            linkEltQname = modelLink.qname
            for linkChild in modelLink:
                linkChildArcrole = linkChild.get(
                    "{http://www.w3.org/1999/xlink}arcrole")
                if linkChild.get("{http://www.w3.org/1999/xlink}type"
                                 ) == "arc" and linkChildArcrole:
                    if isFootnoteRel:  # arcrole is fact-footnote or other custom footnote relationship
                        arcs.append(linkChild)
                    elif isDimensionRel:
                        if XbrlConst.isDimensionArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif isFormulaRel:
                        if XbrlConst.isFormulaArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif isTableRenderingRel:
                        if XbrlConst.isTableRenderingArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif (linkChildArcrole in arcrole
                          and (arcqname is None or arcqname == linkChild.qname)
                          and
                          (linkqname is None or linkqname == linkEltQname)):
                        arcs.append(linkChild)

            # build network
            for arcElement in arcs:
                fromLabel = arcElement.get(
                    "{http://www.w3.org/1999/xlink}from")
                toLabel = arcElement.get("{http://www.w3.org/1999/xlink}to")
                for fromResource in modelLink.labeledResources[fromLabel]:
                    for toResource in modelLink.labeledResources[toLabel]:
                        if isinstance(
                                fromResource,
                            (ModelResource, LocPrototype)) and isinstance(
                                toResource, (ModelResource, LocPrototype)):
                            modelRel = ModelDtsObject.ModelRelationship(
                                modelLink.modelDocument, arcElement,
                                fromResource.dereference(),
                                toResource.dereference())
                            modelRelEquivalenceHash = modelRel.equivalenceHash
                            if modelRelEquivalenceHash not in relationships:
                                relationships[
                                    modelRelEquivalenceHash] = modelRel
                            else:  # use equivalenceKey instead of hash
                                otherRel = relationships[
                                    modelRelEquivalenceHash]
                                if otherRel is not USING_EQUIVALENCE_KEY:  # move equivalentRel to use key instead of hasn
                                    if modelRel.isIdenticalTo(otherRel):
                                        continue  # skip identical arc
                                    relationships[
                                        otherRel.equivalenceKey] = otherRel
                                    relationships[
                                        modelRelEquivalenceHash] = USING_EQUIVALENCE_KEY
                                modelRelEquivalenceKey = modelRel.equivalenceKey  # this is a complex tuple to compute, get once for below
                                if modelRelEquivalenceKey not in relationships or \
                                   modelRel.priorityOver(relationships[modelRelEquivalenceKey]):
                                    relationships[
                                        modelRelEquivalenceKey] = modelRel

        #reduce effective arcs and order relationships...
        self.modelRelationshipsFrom = None
        self.modelRelationshipsTo = None
        self.modelConceptRoots = None
        self.modellinkRoleUris = None
        orderRels = defaultdict(list)
        for modelRel in relationships.values():
            if (modelRel is not USING_EQUIVALENCE_KEY
                    and (includeProhibits or not modelRel.isProhibited)):
                orderRels[modelRel.order].append(modelRel)
        self.modelRelationships = [
            modelRel for order in sorted(orderRels.keys())
            for modelRel in orderRels[order]
        ]
        modelXbrl.relationshipSets[relationshipSetKey] = self
Ejemplo n.º 47
0
    def __init__(self, modelXbrl, arcrole, linkrole=None, linkqname=None, arcqname=None, includeProhibits=False):
        self.isChanged = False
        self.modelXbrl = modelXbrl
        self.arcrole = arcrole
        self.linkrole = linkrole
        self.linkqname = linkqname
        self.arcqname = arcqname

        baseSetKey = (arcrole, linkrole, linkqname, arcqname)
        relationshipSetKey = (arcrole, linkrole, linkqname, arcqname, includeProhibits)

        # base sets does not care about the #includeProhibits
        if baseSetKey in self.modelXbrl.baseSets:
            modelLinks = self.modelXbrl.baseSets[baseSetKey]
        else:
            modelLinks = []

        # gather arcs
        relationships = {}
        isDimensionRel = self.arcrole == "XBRL-dimensions"  # all dimensional relationship arcroles
        isFormulaRel = self.arcrole == "XBRL-formulae"  # all formula relationship arcroles
        isEuRenderingRel = self.arcrole == "EU-rendering"
        isFootnoteRel = self.arcrole == "XBRL-footnotes"  # all footnote relationship arcroles

        for modelLink in modelLinks:
            arcs = []
            linkEltQname = modelLink.qname
            for linkChild in modelLink.element.childNodes:
                if (
                    linkChild.nodeType == 1
                    and linkChild.getAttributeNS(XbrlConst.xlink, "type") == "arc"
                    and linkChild.hasAttributeNS(XbrlConst.xlink, "arcrole")
                ):
                    linkChildArcrole = linkChild.getAttributeNS(XbrlConst.xlink, "arcrole")
                    linkChildQname = linkChild
                    if isFootnoteRel:
                        arcs.append(linkChild)
                    elif isDimensionRel:
                        if XbrlConst.isDimensionArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif isFormulaRel:
                        if XbrlConst.isFormulaArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif isEuRenderingRel:
                        if XbrlConst.isEuRenderingArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif (
                        arcrole == linkChildArcrole
                        and (arcqname is None or arcqname == linkChildQname)
                        and (linkqname is None or linkqname == linkEltQname)
                    ):
                        arcs.append(linkChild)

            # build network
            for arcElement in arcs:
                arcrole = arcElement.getAttributeNS(XbrlConst.xlink, "arcrole")
                fromLabel = arcElement.getAttributeNS(XbrlConst.xlink, "from")
                toLabel = arcElement.getAttributeNS(XbrlConst.xlink, "to")
                for fromResource in modelLink.labeledResources[fromLabel]:
                    for toResource in modelLink.labeledResources[toLabel]:
                        modelRel = ModelObject.createRelationship(
                            modelLink.modelDocument, arcElement, fromResource.dereference(), toResource.dereference()
                        )
                        modelRelEquivalenceKey = (
                            modelRel.equivalenceKey
                        )  # this is a complex tuple to compute, get once for below
                        if modelRelEquivalenceKey not in relationships or modelRel.priorityOver(
                            relationships[modelRelEquivalenceKey]
                        ):
                            relationships[modelRelEquivalenceKey] = modelRel

        # reduce effective arcs and order relationships...
        self.modelRelationships = []
        self.modelRelationshipsFrom = None
        self.modelRelationshipsTo = None
        self.modelConceptRoots = None
        self.modellinkRoleUris = None
        orderRels = defaultdict(list)
        for modelRel in relationships.values():
            if includeProhibits or not modelRel.isProhibited:
                orderRels[modelRel.order].append(modelRel)
        for order in sorted(orderRels.keys()):
            for modelRel in orderRels[order]:
                self.modelRelationships.append(modelRel)
        modelXbrl.relationshipSets[relationshipSetKey] = self
Ejemplo n.º 48
0
    def view(self, firstTime=False, relationshipSet=None):
        self.blockSelectEvent = 1
        self.blockViewModelObject = 0
        self.tag_has = defaultdict(list) # temporary until Tk 8.6
        # relationship set based on linkrole parameter, to determine applicable linkroles
        if relationshipSet is None:
            relationshipSet = groupRelationshipSet(self.modelXbrl, self.arcrole, self.linkrole, self.linkqname, self.arcqname)
        if not relationshipSet:
            self.modelXbrl.modelManager.addToLog(_("no relationships for {0}").format(groupRelationshipLabel(self.arcrole)))
            return False
        
        if firstTime:
            self.showReferences = False
            # set up treeView widget and tabbed pane
            hdr = self.treeColHdr if self.treeColHdr else _("{0} Relationships").format(groupRelationshipLabel(self.arcrole))
            self.treeView.heading("#0", text=hdr)
            if self.showColumns:
                if self.arcrole == XbrlConst.parentChild: # extra columns
                    self.treeView.column("#0", width=300, anchor="w")
                    self.treeView["columns"] = ("preferredLabel", "type", "references")
                    self.treeView.column("preferredLabel", width=64, anchor="w", stretch=False)
                    self.treeView.heading("preferredLabel", text=_("Pref. Label"))
                    self.treeView.column("type", width=100, anchor="w", stretch=False)
                    self.treeView.heading("type", text=_("Type"))
                    self.treeView.column("references", width=200, anchor="w", stretch=False)
                    self.treeView.heading("references", text=_("References"))
                elif self.arcrole == XbrlConst.summationItem: # extra columns
                    self.treeView.column("#0", width=300, anchor="w")
                    self.treeView["columns"] = ("weight", "balance")
                    self.treeView.column("weight", width=48, anchor="w", stretch=False)
                    self.treeView.heading("weight", text=_("Weight"))
                    self.treeView.column("balance", width=70, anchor="w", stretch=False)
                    self.treeView.heading("balance", text=_("Balance"))
                elif self.arcrole == "XBRL-dimensions":    # add columns for dimensional information
                    self.treeView.column("#0", width=300, anchor="w")
                    self.treeView["columns"] = ("arcrole", "contextElement", "closed", "usable")
                    self.treeView.column("arcrole", width=100, anchor="w", stretch=False)
                    self.treeView.heading("arcrole", text="Arcrole")
                    self.treeView.column("contextElement", width=50, anchor="center", stretch=False)
                    self.treeView.heading("contextElement", text="Context")
                    self.treeView.column("closed", width=40, anchor="center", stretch=False)
                    self.treeView.heading("closed", text="Closed")
                    self.treeView.column("usable", width=40, anchor="center", stretch=False)
                    self.treeView.heading("usable", text="Usable")
                elif self.arcrole == "Table-rendering":    # add columns for dimensional information
                    self.treeView.column("#0", width=160, anchor="w")
                    self.treeView["columns"] = ("axis", "abstract", "merge", "header", "priItem", "dims")
                    self.treeView.column("axis", width=28, anchor="center", stretch=False)
                    self.treeView.heading("axis", text="Axis")
                    self.treeView.column("abstract", width=24, anchor="center", stretch=False)
                    self.treeView.heading("abstract", text="Abs")
                    self.treeView.column("merge", width=26, anchor="center", stretch=False)
                    self.treeView.heading("merge", text="Mrg")
                    self.treeView.column("header", width=160, anchor="w", stretch=False)
                    self.treeView.heading("header", text="Header")
                    self.treeView.column("priItem", width=100, anchor="w", stretch=False)
                    self.treeView.heading("priItem", text="Primary Item")
                    self.treeView.column("dims", width=150, anchor="w", stretch=False)
                    self.treeView.heading("dims", text=_("Dimensions"))
                elif isinstance(self.arcrole, (list,tuple)) or XbrlConst.isResourceArcrole(self.arcrole):
                    self.isResourceArcrole = True
                    self.showReferences = isinstance(self.arcrole, _STR_BASE) and self.arcrole.endswith("-reference")
                    self.treeView.column("#0", width=160, anchor="w")
                    self.treeView["columns"] = ("arcrole", "resource", "resourcerole", "lang")
                    self.treeView.column("arcrole", width=100, anchor="w", stretch=False)
                    self.treeView.heading("arcrole", text="Arcrole")
                    self.treeView.column("resource", width=60, anchor="w", stretch=False)
                    self.treeView.heading("resource", text="Resource")
                    self.treeView.column("resourcerole", width=100, anchor="w", stretch=False)
                    self.treeView.heading("resourcerole", text="Resource Role")
                    self.treeView.column("lang", width=36, anchor="w", stretch=False)
                    self.treeView.heading("lang", text="Lang")
        self.clearTreeView()
        self.id = 1
        
        # sort URIs by definition
        linkroleUris = []
        for linkroleUri in relationshipSet.linkRoleUris:
            modelRoleTypes = self.modelXbrl.roleTypes.get(linkroleUri)
            if modelRoleTypes:
                roledefinition = ((self.hasTableIndex and getattr(modelRoleTypes[0], "_tableIndex", False)) or
                                  modelRoleTypes[0].genLabel(lang=self.lang, strip=True) or 
                                  modelRoleTypes[0].definition or 
                                  linkroleUri)
                roleId = modelRoleTypes[0].objectId(self.id)
            else:
                roledefinition = linkroleUri
                roleId = "node{0}".format(self.id)
            self.id += 1
            linkroleUris.append((roledefinition, linkroleUri, roleId))
        linkroleUris.sort()
        # for each URI in definition order
        tableGroup = ""
        for roledefinition, linkroleUri, roleId in linkroleUris:
            if self.showLinkroles:
                if isinstance(roledefinition, tuple): # tableGroup
                    nextTableGroup, order, roledefinition = roledefinition
                    if tableGroup != nextTableGroup:
                        self.treeView.insert("", "end", nextTableGroup, text=nextTableGroup[1:], tags=("Group",))
                        if not tableGroup: # first tableGroup item, expand it
                            self.setTreeItemOpen(nextTableGroup,open=True)
                        tableGroup = nextTableGroup
                linknode = self.treeView.insert(tableGroup, "end", roleId, text=roledefinition, tags=("ELR",))
            else:
                linknode = ""
            if self.showRelationships:
                linkRelationshipSet = groupRelationshipSet(self.modelXbrl, self.arcrole, linkroleUri, self.linkqname, self.arcqname)
                for rootConcept in linkRelationshipSet.rootConcepts:
                    self.viewConcept(rootConcept, rootConcept, "", self.labelrole, linknode, 1, linkRelationshipSet, set())
                    self.tag_has[linkroleUri].append(linknode)

        if self.expandAllOnFirstDisplay:
            self.expandAll()
Ejemplo n.º 49
0
def checkDTSdocument(val, modelDocument, isFilingDocument):
    for hrefElt, _hrefedDoc, hrefId in modelDocument.hrefObjects:
        if hrefId:  #check scheme regardless of whether document loaded
            # check all xpointer schemes
            for scheme, _path in XmlUtil.xpointerSchemes(hrefId):
                if scheme == "element" and val.validateDisclosureSystem:
                    val.modelXbrl.error(
                        ("EFM.6.03.06", "GFM.1.01.03"),
                        _("Href %(elementHref)s may only have shorthand xpointers"
                          ),
                        edgarCode="cp-0306-Href-Xpointers",
                        modelObject=hrefElt,
                        elementHref=hrefElt.get(
                            "{http://www.w3.org/1999/xlink}href"))

    if not isFilingDocument:
        return  # not a filing's extension document

    if modelDocument.type == ModelDocument.Type.SCHEMA:
        if modelDocument.targetNamespace is not None and len(
                modelDocument.targetNamespace) > 85:
            l = len(modelDocument.targetNamespace.encode("utf-8"))
            if l > 255:
                val.modelXbrl.error(
                    "EFM.6.07.30",
                    _("Shorten this declaration URI from %(length)s to 255 bytes or fewer in UTF-8: %(value)s."
                      ),
                    edgarCode="du-0730-uri-length-limit",
                    modelObject=modelDocument.xmlRootElement,
                    length=l,
                    targetNamespace=modelDocument.targetNamespace,
                    value=modelDocument.targetNamespace)

    if modelDocument.type in (ModelDocument.Type.SCHEMA,
                              ModelDocument.Type.LINKBASE):
        isSchema = modelDocument.type == ModelDocument.Type.SCHEMA
        if isSchema:
            for elt in modelDocument.xmlRootElement.iter(
                    tag="{http://www.w3.org/2001/XMLSchema}*"):
                if elt.namespaceURI == XbrlConst.xsd:
                    localName = elt.localName
                    if localName in {"element", "complexType", "simpleType"}:
                        name = elt.get("name")
                        if name and len(name) > 64:
                            l = len(name.encode("utf-8"))
                            if l > 200:
                                val.modelXbrl.error(
                                    "EFM.6.07.29",
                                    _("Shorten this declaration name from %(length)s to 200 bytes or fewer in UTF-8: %(name)s"
                                      ),
                                    edgarCode="du-0729-name-length-limit",
                                    modelObject=elt,
                                    element=localName,
                                    name=name,
                                    length=l)

    for elt in modelDocument.xmlRootElement.iter():
        if isinstance(elt, ModelObject):
            xlinkType = elt.get("{http://www.w3.org/1999/xlink}type")
            xlinkRole = elt.get("{http://www.w3.org/1999/xlink}role")
            if elt.namespaceURI == XbrlConst.link:
                # check schema roleTypes
                if elt.localName in ("roleType", "arcroleType"):
                    uriAttr = {
                        "roleType": "roleURI",
                        "arcroleType": "arcroleURI"
                    }[elt.localName]
                    roleURI = elt.get(uriAttr)
                    if len(roleURI) > 85:
                        l = len(roleURI.encode("utf-8"))
                        if l > 255:
                            val.modelXbrl.error(
                                "EFM.6.07.30",
                                _("Shorten this declaration URI from %(length)s to 255 bytes or fewer in UTF-8: %(value)s."
                                  ),
                                edgarCode="du-0730-uri-length-limit",
                                modelObject=elt,
                                element=elt.qname,
                                attribute=uriAttr,
                                length=l,
                                roleURI=roleURI,
                                value=roleURI)

                if elt.localName == "arcroleRef":
                    refUri = elt.get("arcroleURI")
                    hrefAttr = elt.get("{http://www.w3.org/1999/xlink}href")
                    hrefUri, hrefId = UrlUtil.splitDecodeFragment(hrefAttr)
                    if hrefUri not in val.disclosureSystem.standardTaxonomiesDict:
                        val.modelXbrl.error(
                            ("EFM.6.09.06", "GFM.1.04.06"),
                            _("An arcroleRef element refers to %(xlinkHref)s, an arcrole, %(refURI)s, that is not defined in a standard taxonomy. "
                              "Please recheck submission."),
                            edgarCode="fs-0906-Custom-Arcrole-Referenced",
                            modelObject=elt,
                            refURI=refUri,
                            xlinkHref=hrefUri)
            if modelDocument.type == ModelDocument.Type.INLINEXBRL and elt.namespaceURI in XbrlConst.ixbrlAll:
                if elt.localName == "footnote":
                    if val.validateGFM:
                        if elt.get("{http://www.w3.org/1999/xlink}arcrole"
                                   ) != XbrlConst.factFootnote:
                            # must be in a nonDisplay div
                            if not any(
                                    inlineDisplayNonePattern.search(
                                        e.get("style") or "")
                                    for e in XmlUtil.ancestors(
                                        elt, XbrlConst.xhtml, "div")):
                                val.modelXbrl.error(
                                    ("EFM.N/A", "GFM:1.10.16"),
                                    _("Inline XBRL footnote %(footnoteID)s must be in non-displayable div due to arcrole %(arcrole)s"
                                      ),
                                    modelObject=elt,
                                    footnoteID=elt.get("footnoteID"),
                                    arcrole=elt.get(
                                        "{http://www.w3.org/1999/xlink}arcrole"
                                    ))

                        if not elt.get(
                                "{http://www.w3.org/XML/1998/namespace}lang"):
                            val.modelXbrl.error(
                                ("EFM.N/A", "GFM:1.10.13"),
                                _("Inline XBRL footnote %(footnoteID)s is missing an xml:lang attribute"
                                  ),
                                modelObject=elt,
                                footnoteID=id)
            if xlinkType == "extended":
                if not xlinkRole or xlinkRole == "":
                    val.modelXbrl.error(
                        ("EFM.6.09.04", "GFM.1.04.04"),
                        "The %(element)s element requires an xlink:role such as the default, 'http://www.xbrl.org/2003/role/label'.  "
                        "Please recheck submission.",
                        edgarCode="fs-0904-Resource-Role-Missing",
                        modelObject=elt,
                        element=elt.qname)
                if not val.extendedElementName:
                    val.extendedElementName = elt.qname
                elif val.extendedElementName != elt.qname:
                    val.modelXbrl.error(
                        ("EFM.6.09.07", "GFM:1.04.07"),
                        _("Your filing contained extended type links with roles of different namesapces and local names, %(element)s "
                          "and %(element2)s in the same linkbase, %(refUrl)s.  Please recheck your submission and ensure that all "
                          "extended-type links in a single linkbase have the same namespace and local name."
                          ),
                        edgarCode="cp-0907-Linkbases-Distinct",
                        refUrl=elt.modelDocument.basename,
                        modelObject=elt,
                        element=elt.qname,
                        element2=val.extendedElementName)
            elif xlinkType == "resource":
                if not xlinkRole:
                    val.modelXbrl.error(
                        ("EFM.6.09.04", "GFM.1.04.04"),
                        _("The %(element)s element requires an xlink:role such as the default, 'http://www.xbrl.org/2003/role/label'.  "
                          "Please recheck submission."),
                        edgarCode="fs-0904-Resource-Role-Missing",
                        modelObject=elt,
                        element=elt.qname)
                elif not XbrlConst.isStandardRole(xlinkRole):
                    modelsRole = val.modelXbrl.roleTypes.get(xlinkRole)
                    if (modelsRole is None or len(modelsRole) == 0
                            or modelsRole[0].modelDocument.targetNamespace
                            not in val.disclosureSystem.standardTaxonomiesDict
                        ):
                        val.modelXbrl.error(
                            ("EFM.6.09.05", "GFM.1.04.05"),
                            _("The %(element)s element has a role, %(roleDefinition)s, that is not defined in a standard taxonomy, "
                              "resource labeled %(xlinkLabel)s.  Please recheck submission."
                              ),
                            edgarCode="fs-0905-Custom-Resource-Role-Used",
                            modelObject=elt,
                            xlinkLabel=elt.get(
                                "{http://www.w3.org/1999/xlink}label"),
                            role=xlinkRole,
                            element=elt.qname,
                            roleDefinition=val.modelXbrl.roleTypeDefinition(
                                xlinkRole))
            elif xlinkType == "arc":
                if elt.get("priority") is not None:
                    priority = elt.get("priority")
                    try:
                        if int(priority) >= 10:
                            val.modelXbrl.error(
                                ("EFM.6.09.09", "GFM.1.04.08"),
                                _("The priority attribute %(priority)s has a value of ten or greater, on arc %(arcElement)s from %(xlinkFrom)s to %(xlinkTo)s. "
                                  "Please change the priority to value less than 10 and resubmit."
                                  ),
                                edgarCode=
                                "du-0909-Relationship-Priority-Not-Less-Than-Ten",
                                modelObject=elt,
                                arcElement=elt.qname,
                                xlinkFrom=elt.get(
                                    "{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get(
                                    "{http://www.w3.org/1999/xlink}to"),
                                priority=priority)
                    except (ValueError):
                        val.modelXbrl.error(
                            ("EFM.6.09.09", "GFM.1.04.08"),
                            _("The priority attribute %(priority)s has a value of ten or greater, on arc %(arcElement)s from %(xlinkFrom)s to %(xlinkTo)s. "
                              "Please change the priority to value less than 10 and resubmit."
                              ),
                            edgarCode=
                            "du-0909-Relationship-Priority-Not-Less-Than-Ten",
                            modelObject=elt,
                            arcElement=elt.qname,
                            xlinkFrom=elt.get(
                                "{http://www.w3.org/1999/xlink}from"),
                            xlinkTo=elt.get(
                                "{http://www.w3.org/1999/xlink}to"),
                            priority=priority)
                if elt.namespaceURI == XbrlConst.link:
                    if elt.localName == "presentationArc" and not elt.get(
                            "order"):
                        val.modelXbrl.error(
                            ("EFM.6.12.01", "GFM.1.06.01"),
                            _("The presentation relationship from %(conceptFrom)s to %(conceptTo)s does not have an order attribute.  "
                              "Please provide a value."),
                            edgarCode="rq-1201-Presentation-Order-Missing",
                            modelObject=elt,
                            xlinkFrom=elt.get(
                                "{http://www.w3.org/1999/xlink}from"),
                            xlinkTo=elt.get(
                                "{http://www.w3.org/1999/xlink}to"),
                            conceptFrom=arcFromConceptQname(elt),
                            conceptTo=arcToConceptQname(elt))
                    elif elt.localName == "calculationArc":
                        if not elt.get("order"):
                            val.modelXbrl.error(
                                ("EFM.6.14.01", "GFM.1.07.01"),
                                _("The calculation relationship from %(conceptFrom)s to %(conceptTo)s does not have an order attribute."
                                  ),
                                edgarCode=
                                "du-1401-Calculation-Relationship-Order-Missing",
                                modelObject=elt,
                                xlinkFrom=elt.get(
                                    "{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get(
                                    "{http://www.w3.org/1999/xlink}to"),
                                conceptFrom=arcFromConceptQname(elt),
                                conceptTo=arcToConceptQname(elt))
                        try:
                            weightAttr = elt.get("weight")
                            weight = float(weightAttr)
                            if not weight in (1, -1):
                                val.modelXbrl.error(
                                    ("EFM.6.14.02", "GFM.1.07.02"),
                                    _("Weight value %(weight)s on the calculation relationship from %(conceptFrom)s to %(conceptTo)s "
                                      "must be equal to 1 or to -1. Please recheck submission."
                                      ),
                                    edgarCode=
                                    "fs-1402-Calculation-Relationship-Weight-Not-Unitary",
                                    modelObject=elt,
                                    xlinkFrom=elt.get(
                                        "{http://www.w3.org/1999/xlink}from"),
                                    xlinkTo=elt.get(
                                        "{http://www.w3.org/1999/xlink}to"),
                                    conceptFrom=arcFromConceptQname(elt),
                                    conceptTo=arcToConceptQname(elt),
                                    weight=weightAttr)
                        except ValueError:
                            val.modelXbrl.error(
                                ("EFM.6.14.02", "GFM.1.07.02"),
                                _("Weight value %(weight)s on the calculation relationship from %(conceptFrom)s to %(conceptTo)s "
                                  "must be equal to 1 or to -1. Please recheck submission."
                                  ),
                                edgarCode=
                                "fs-1402-Calculation-Relationship-Weight-Not-Unitary",
                                modelObject=elt,
                                xlinkFrom=elt.get(
                                    "{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get(
                                    "{http://www.w3.org/1999/xlink}to"),
                                conceptFrom=arcFromConceptQname(elt),
                                conceptTo=arcToConceptQname(elt),
                                weight=weightAttr)
                    elif elt.localName == "definitionArc":
                        if not elt.get("order"):
                            val.modelXbrl.error(
                                ("EFM.6.16.01", "GFM.1.08.01"),
                                _("The Definition relationship from %(conceptFrom)s to %(conceptTo)s does not have an order attribute."
                                  ),
                                edgarCode=
                                "du-1601-Definition-Relationship-Order-Missing",
                                modelObject=elt,
                                xlinkFrom=elt.get(
                                    "{http://www.w3.org/1999/xlink}from"),
                                xlinkTo=elt.get(
                                    "{http://www.w3.org/1999/xlink}to"),
                                conceptFrom=arcFromConceptQname(elt),
                                conceptTo=arcToConceptQname(elt))
Ejemplo n.º 50
0
    def __init__(self, modelXbrl, arcrole, linkrole=None, linkqname=None, arcqname=None, includeProhibits=False):
        self.isChanged = False
        self.modelXbrl = modelXbrl
        self.arcrole = arcrole
        self.linkrole = linkrole
        self.linkqname = linkqname
        self.arcqname = arcqname

        relationshipSetKey = (arcrole, linkrole, linkqname, arcqname, includeProhibits) 
            
        # base sets does not care about the #includeProhibits
        if not isinstance(arcrole,(tuple,frozenset)):
            modelLinks = self.modelXbrl.baseSets.get((arcrole, linkrole, linkqname, arcqname), [])
        else: # arcrole is a set of arcroles
            modelLinks = []
            for ar in arcrole:
                modelLinks.extend(self.modelXbrl.baseSets.get((ar, linkrole, linkqname, arcqname), []))
            
        # gather arcs
        relationships = {}
        isDimensionRel =  self.arcrole == "XBRL-dimensions" # all dimensional relationship arcroles
        isFormulaRel =  self.arcrole == "XBRL-formulae" # all formula relationship arcroles
        isTableRenderingRel = self.arcrole == "Table-rendering"
        isFootnoteRel =  self.arcrole == "XBRL-footnotes" # all footnote relationship arcroles
        if not isinstance(arcrole,(tuple,frozenset)):
            arcrole = (arcrole,)
        
        for modelLink in modelLinks:
            arcs = []
            linkEltQname = modelLink.qname
            for linkChild in modelLink:
                linkChildArcrole = linkChild.get("{http://www.w3.org/1999/xlink}arcrole")
                if linkChild.get("{http://www.w3.org/1999/xlink}type") == "arc" and linkChildArcrole:
                    linkChildQname = linkChild
                    if isFootnoteRel:
                        arcs.append(linkChild)
                    elif isDimensionRel: 
                        if XbrlConst.isDimensionArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif isFormulaRel:
                        if XbrlConst.isFormulaArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif isTableRenderingRel:
                        if XbrlConst.isTableRenderingArcrole(linkChildArcrole):
                            arcs.append(linkChild)
                    elif (linkChildArcrole in arcrole and 
                          (arcqname is None or arcqname == linkChildQname) and 
                          (linkqname is None or linkqname == linkEltQname)):
                        arcs.append(linkChild)
                        
            # build network
            for arcElement in arcs:
                fromLabel = arcElement.get("{http://www.w3.org/1999/xlink}from")
                toLabel = arcElement.get("{http://www.w3.org/1999/xlink}to")
                for fromResource in modelLink.labeledResources[fromLabel]:
                    for toResource in modelLink.labeledResources[toLabel]:
                        if isinstance(fromResource,ModelResource) and isinstance(toResource,ModelResource):
                            modelRel = ModelDtsObject.ModelRelationship(modelLink.modelDocument, arcElement, fromResource.dereference(), toResource.dereference())
                            modelRelEquivalenceKey = modelRel.equivalenceKey    # this is a complex tuple to compute, get once for below
                            if modelRelEquivalenceKey not in relationships or \
                               modelRel.priorityOver(relationships[modelRelEquivalenceKey]):
                                relationships[modelRelEquivalenceKey] = modelRel

        #reduce effective arcs and order relationships...
        self.modelRelationshipsFrom = None
        self.modelRelationshipsTo = None
        self.modelConceptRoots = None
        self.modellinkRoleUris = None
        orderRels = defaultdict(list)
        for modelRel in relationships.values():
            if includeProhibits or not modelRel.isProhibited:
                orderRels[modelRel.order].append(modelRel)
        self.modelRelationships = [modelRel
                                   for order in sorted(orderRels.keys())
                                   for modelRel in orderRels[order]]
        modelXbrl.relationshipSets[relationshipSetKey] = self
Ejemplo n.º 51
0
def groupRelationshipLabel(arcrole):
    if isinstance(arcrole, (list, tuple)):  # (group-name, [arcroles])
        arcroleName = arcrole[0]
    else:
        arcroleName = XbrlConst.baseSetArcroleLabel(arcrole)[1:]
    return arcroleName