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()
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()
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))
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") '''
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))
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))
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" ) '''