Exemple #1
0
 def __init__(self, modelXbrl):
     self.modelXbrl = modelXbrl
     if modelXbrl.modelManager.validateDisclosureSystem:
         if modelXbrl.modelManager.disclosureSystem.HMRC:
             self.instValidator = ValidateHmrc.ValidateHmrc(modelXbrl)
         else:
             self.instValidator = ValidateFiling.ValidateFiling(modelXbrl)
         self.formulaValidator = ValidateXbrl.ValidateXbrl(modelXbrl)
     else:
         self.instValidator = ValidateXbrl.ValidateXbrl(modelXbrl)
         self.formulaValidator = self.instValidator
Exemple #2
0
 def __init__(self, modelXbrl):
     self.modelXbrl = modelXbrl
     if modelXbrl.modelManager.validateDisclosureSystem:
         self.instValidator = ValidateXbrl.ValidateXbrl(modelXbrl)
         self.formulaValidator = ValidateXbrl.ValidateXbrl(modelXbrl)
     else:
         self.instValidator = ValidateXbrl.ValidateXbrl(modelXbrl)
         self.formulaValidator = self.instValidator
     if hasattr(modelXbrl,"fileSource"):
         self.useFileSource = modelXbrl.fileSource
     else:
         self.useFileSource = None
Exemple #3
0
 def __init__(self, modelXbrl):
     self.modelXbrl = modelXbrl
     if modelXbrl.modelManager.validateDisclosureSystem:
         if modelXbrl.modelManager.disclosureSystem.HMRC: # deprecated non-plugin validator
             self.instValidator = ValidateHmrc.ValidateHmrc(modelXbrl)
         elif modelXbrl.modelManager.disclosureSystem.EFMorGFM or modelXbrl.modelManager.disclosureSystem.SBRNL: # deprecated non-plugin validator
             self.instValidator = ValidateFiling.ValidateFiling(modelXbrl)
         else: # custom validator, probably a plug-in
             self.instValidator = ValidateXbrl.ValidateXbrl(modelXbrl)
         self.formulaValidator = ValidateXbrl.ValidateXbrl(modelXbrl)
     else:
         self.instValidator = ValidateXbrl.ValidateXbrl(modelXbrl)
         self.formulaValidator = self.instValidator
     if hasattr(modelXbrl,"fileSource"):
         self.useFileSource = modelXbrl.fileSource
     else:
         self.useFileSource = None
Exemple #4
0
    def __init__(self, cntlr, isCmdLine=False):
        self.cntlr = cntlr

        # setup tester
        xml = "<rootElement/>"
        self.modelXbrl = ModelXbrl.create(cntlr.modelManager, ModelDocument.Type.UnknownNonXML, initialXml=xml, isEntry=True)
        self.validator = ValidateXbrl.ValidateXbrl(self.modelXbrl)
        self.validator.validate(self.modelXbrl)  # required to set up
        cntlr.showStatus(_("Initializing Formula Grammar"))
        XPathParser.initializeParser(cntlr.modelManager)
        cntlr.showStatus(None)

        self.trRegs = sorted(ixtNamespaces.keys())
        self.trPrefixNSs = dict((qn.prefix, qn.namespaceURI) 
                                  for qn in self.modelXbrl.modelManager.customTransforms.keys())
        self.trRegs.extend(sorted(self.trPrefixNSs.keys()))
        self.trPrefixNSs.update(ixtNamespaces)
Exemple #5
0
 def watchCycle(self):
     while not self.stopRequested:
         rssWatchOptions = self.rssModelXbrl.modelManager.rssWatchOptions
         
         # check rss expiration
         rssHeaders = self.cntlr.webCache.getheaders(self.rssModelXbrl.modelManager.rssWatchOptions.get("feedSourceUri"))
         expires = parseRfcDatetime(rssHeaders.get("expires"))
         reloadNow = True # texpires and expires > datetime.datetime.now()
         
         # reload rss feed
         self.rssModelXbrl.reload('checking RSS items', reloadCache=reloadNow)
         if self.stopRequested: break
         # setup validator
         postLoadActions = []
         if rssWatchOptions.get("validateDisclosureSystemRules"):
             self.instValidator = ValidateFiling.ValidateFiling(self.rssModelXbrl)
             postLoadActions.append(_("validating"))
         elif rssWatchOptions.get("validateXbrlRules") or rssWatchOptions.get("validateFormulaAssertions"):
             self.instValidator = ValidateXbrl.ValidateXbrl(self.rssModelXbrl)
             postLoadActions.append(_("validating"))
             if (rssWatchOptions.get("validateFormulaAssertions")):
                 postLoadActions.append(_("running formulas"))
         else:
             self.instValidator = None
            
         matchTextExpr = rssWatchOptions.get("matchTextExpr") 
         if matchTextExpr:
             matchPattern = re.compile(matchTextExpr)
             postLoadActions.append(_("matching text"))
         else:
             matchPattern= None
         postLoadAction = ', '.join(postLoadActions)
         
         # anything to check new filings for
         if (rssWatchOptions.get("validateDisclosureSystemRules") or
             rssWatchOptions.get("validateXbrlRules") or
             rssWatchOptions.get("validateCalcLinkbase") or
             rssWatchOptions.get("validateFormulaAssertions") or
             rssWatchOptions.get("alertMatchedFactText") or
             any(pluginXbrlMethod(rssWatchOptions)
                 for pluginXbrlMethod in pluginClassMethods("RssWatch.HasWatchAction"))
             ):
             # form keys in ascending order of pubdate
             pubDateRssItems = []
             for rssItem in self.rssModelXbrl.modelDocument.rssItems:
                 pubDateRssItems.append((rssItem.pubDate,rssItem.objectId()))
             
             for pubDate, rssItemObjectId in sorted(pubDateRssItems):
                 rssItem = self.rssModelXbrl.modelObject(rssItemObjectId)
                 # update ui thread via modelManager (running in background here)
                 self.rssModelXbrl.modelManager.viewModelObject(self.rssModelXbrl, rssItem.objectId())
                 if self.stopRequested:
                     break
                 latestPubDate = XmlUtil.datetimeValue(rssWatchOptions.get("latestPubDate"))
                 if (latestPubDate and 
                     rssItem.pubDate < latestPubDate):
                     continue
                 try:
                     # try zipped URL if possible, else expanded instance document
                     modelXbrl = ModelXbrl.load(self.rssModelXbrl.modelManager, 
                                                openFileSource(rssItem.zippedUrl, self.cntlr),
                                                postLoadAction)
                     if self.stopRequested:
                         modelXbrl.close()
                         break
                     
                     emailAlert = False
                     if modelXbrl.modelDocument is None:
                         modelXbrl.error("arelle.rssWatch",
                                         _("RSS item %(company)s %(form)s document not loaded: %(date)s"),
                                         modelXbrl=modelXbrl, company=rssItem.companyName, 
                                         form=rssItem.formType, date=rssItem.filingDate)
                         rssItem.status = "not loadable"
                     else:
                         # validate schema, linkbase, or instance
                         if self.stopRequested:
                             modelXbrl.close()
                             break
                         if self.instValidator:
                             self.instValidator.validate(modelXbrl)
                             if modelXbrl.errors and rssWatchOptions.get("alertValiditionError"):
                                 emailAlert = True
                         for pluginXbrlMethod in pluginClassMethods("RssWatch.DoWatchAction"):  
                             pluginXbrlMethod(modelXbrl, rssWatchOptions, rssItem)      
                         # check match expression
                         if matchPattern:
                             for fact in modelXbrl.factsInInstance:
                                 v = fact.value
                                 if v is not None:
                                     m = matchPattern.search(v)
                                     if m:
                                         fr, to = m.span()
                                         msg = _("Fact Variable {0}\n context {1}\n matched text: {2}").format( 
                                                 fact.qname, fact.contextID, v[max(0,fr-20):to+20])
                                         modelXbrl.info("arelle.rssInfo",
                                                        msg,
                                                        modelXbrl=modelXbrl) # msg as code passes it through to the status
                                         if rssWatchOptions.get("alertMatchedFactText"):
                                             emailAlert = True
                                     
                         if (rssWatchOptions.get("formulaFileUri") and rssWatchOptions.get("validateFormulaAssertions") and
                             self.instValidator): 
                             # attach formulas
                             ModelDocument.load(modelXbrl, rssWatchOptions["formulaFileUri"])
                             ValidateFormula.validate(self.instValidator)
                             
                     rssItem.setResults(modelXbrl)
                     modelXbrl.close()
                     del modelXbrl  # completely dereference
                     self.rssModelXbrl.modelManager.viewModelObject(self.rssModelXbrl, rssItem.objectId())
                     if rssItem.assertionUnsuccessful and rssWatchOptions.get("alertAssertionUnsuccessful"):
                         emailAlert = True
                     
                     msg = _("Filing CIK {0}\n "
                              "company {1}\n "
                              "published {2}\n "
                              "form type {3}\n "
                              "filing date {4}\n "
                              "period {5}\n "
                              "year end {6}\n "
                              "results: {7}").format(
                              rssItem.cikNumber,
                              rssItem.companyName,
                              rssItem.pubDate,
                              rssItem.formType,
                              rssItem.filingDate,
                              rssItem.period,
                              rssItem.fiscalYearEnd,
                              rssItem.status)
                     self.rssModelXbrl.info("arelle:rssWatch", msg, modelXbrl=self.rssModelXbrl)
                     emailAddress = rssWatchOptions.get("emailAddress")
                     if emailAlert and emailAddress:
                         self.rssModelXbrl.modelManager.showStatus(_("sending e-mail alert"))
                         import smtplib
                         from email.mime.text import MIMEText
                         emailMsg = MIMEText(msg)
                         emailMsg["Subject"] = _("Arelle RSS Watch alert on {0}").format(rssItem.companyName)
                         emailMsg["From"] = emailAddress
                         emailMsg["To"] = emailAddress
                         smtp = smtplib.SMTP()
                         smtp.sendmail(emailAddress, [emailAddress], emailMsg.as_string())
                         smtp.quit()
                     self.rssModelXbrl.modelManager.showStatus(_("RSS item {0}, {1} completed, status {2}").format(rssItem.companyName, rssItem.formType, rssItem.status), 3500)
                     self.rssModelXbrl.modelManager.cntlr.rssWatchUpdateOption(rssItem.pubDate.strftime('%Y-%m-%dT%H:%M:%S'))
                 except Exception as err:
                     self.rssModelXbrl.error("arelle.rssError",
                                             _("RSS item %(company)s, %(form)s, %(date)s, exception: %(error)s"),
                                             modelXbrl=self.rssModelXbrl, company=rssItem.companyName, 
                                             form=rssItem.formType, date=rssItem.filingDate, error=err,
                                             exc_info=True)
                 if self.stopRequested: break
         if self.stopRequested: 
             self.cntlr.showStatus(_("RSS watch, stop requested"), 10000)
         else:
             import time
             time.sleep(600)
         
     self.thread = None  # close thread
     self.stopRequested = False
     
             
Exemple #6
0
    def validate(self, modelVersReport):
        self.modelVersReport = modelVersReport
        versReport = modelVersReport.modelDocument
        if not hasattr(versReport, "xmlDocument"): # not parsed
            return
        for DTSname in ("fromDTS", "toDTS"):
            DTSmodelXbrl = getattr(versReport, DTSname)
            if DTSmodelXbrl is None or DTSmodelXbrl.modelDocument is None:
                self.modelVersReport.error("vere:invalidDTSIdentifier",
                    _("%(dts)s is missing or not loaded"),
                    modelObject=self, dts=DTSname)
            else:
                # validate DTS
                ValidateXbrl.ValidateXbrl(DTSmodelXbrl).validate(DTSmodelXbrl)
                if len(DTSmodelXbrl.errors) > 0:
                    self.modelVersReport.error("vere:invalidDTSIdentifier",
                        _("%(dts) has errors: %(error)s"),
                        modelObject=DTSmodelXbrl.modelDocument, dts=DTSname, error=DTSmodelXbrl.errors)
        # validate linkbases
        ValidateXbrl.ValidateXbrl(self.modelVersReport).validate(modelVersReport)

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

                        
            
            '''
            # check instance aspect changes
            for iaChange in versReport.instanceAspectChanges:
                # validate related concepts
                for aspectName in ("{http://xbrl.org/2010/versioning-instance-aspects}concept", "{http://xbrl.org/2010/versioning-instance-aspects}member"):
                    for aspectElt in iaChange.iterdescendants(aspectName):
                        # check link attribute
                        link = aspectElement.get("link")
                        if link is not None:
                            iaChange.hrefToModelObject(link, dts)
            '''
            
        self.close()
Exemple #7
0
    def __init__(self, mainWin):
        parent = mainWin.parent
        super(DialogTransformTester, self).__init__(parent)
        self.mainWin = mainWin
        self.parent = parent
        parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)",
                                  parent.geometry())
        dialogX = int(parentGeometry.group(3))
        dialogY = int(parentGeometry.group(4))
        self.selectedGroup = None

        self.transient(self.parent)
        self.title(_("Transformation Tester"))

        frame = Frame(self)

        # setup tester
        xml = "<rootElement/>"
        self.modelXbrl = ModelXbrl.create(mainWin.modelManager,
                                          ModelDocument.Type.UnknownNonXML,
                                          initialXml=xml,
                                          isEntry=True)
        self.validator = ValidateXbrl.ValidateXbrl(self.modelXbrl)
        self.validator.validate(self.modelXbrl)  # required to set up
        mainWin.showStatus(_("Initializing Formula Grammar"))
        XPathParser.initializeParser(mainWin.modelManager)
        mainWin.showStatus(None)

        self.trRegs = sorted(ixtNamespaces.keys())
        self.trReg = self.trRegs[-1]  # default is latest
        self.trPrefixNSs = dict(
            (qn.prefix, qn.namespaceURI)
            for qn in self.modelXbrl.modelManager.customTransforms.keys())
        self.trRegs.extend(sorted(self.trPrefixNSs.keys()))
        self.trPrefixNSs.update(ixtNamespaces)
        self.trNames = self.getTrNames()

        # load grid
        trRegLabel = label(frame, 0, 0, _("Registry:"))
        self.trRegName = gridCombobox(
            frame,
            1,
            0,
            value=self.trReg,
            values=self.trRegs,
            comboboxselected=self.trRegComboBoxSelected)
        trRegToolTipMessage = _("Select Transformation Registry")
        ToolTip(self.trRegName, text=trRegToolTipMessage, wraplength=360)
        ToolTip(trRegLabel, text=trRegToolTipMessage, wraplength=360)

        trNameLabel = label(frame, 0, 1, _("Transform:"))
        self.trNameName = gridCombobox(
            frame,
            1,
            1,
            value="",
            values=self.trNames,
            comboboxselected=self.trNameComboBoxSelected)
        trRegToolTipMessage = _("Select or enter transform")
        ToolTip(self.trRegName, text=trRegToolTipMessage, wraplength=360)
        ToolTip(trRegLabel, text=trRegToolTipMessage, wraplength=360)

        sourceLabel = label(frame, 0, 2, _("Source text:"))
        ToolTip(sourceLabel,
                text=_("Enter the source text which is to be transformed. "),
                wraplength=240)
        self.sourceVar = StringVar()
        self.sourceVar.set("")
        sourceEntry = Entry(frame, textvariable=self.sourceVar, width=50)
        sourceLabel.grid(row=2, column=0, sticky=W)
        sourceEntry.grid(row=2, column=1, sticky=EW, pady=3, padx=3)

        resultLabel = label(frame, 1, 3, _("Result:"))
        ToolTip(sourceLabel, text=_("Transformation result. "), wraplength=240)
        self.resultVar = StringVar()
        self.resultVar.set("")
        resultEntry = Entry(frame, textvariable=self.resultVar, width=50)
        resultLabel.grid(row=3, column=0, sticky=W)
        resultEntry.grid(row=3, column=1, sticky=EW, pady=3, padx=3)

        mainWin.showStatus(None)

        btnPad = 2 if mainWin.isMSW else 0  # buttons too narrow on windows
        okButton = Button(frame,
                          text=_("Transform"),
                          width=8 + btnPad,
                          command=self.ok)
        cancelButton = Button(frame,
                              text=_("Done"),
                              width=4 + btnPad,
                              command=self.close)
        cancelButton.grid(row=4,
                          column=0,
                          sticky=E,
                          columnspan=2,
                          pady=3,
                          padx=3)
        okButton.grid(row=4, column=0, sticky=E, columnspan=2, pady=3, padx=64)
        ToolTip(okButton,
                text=_("Transform the source entered. "),
                wraplength=240)
        ToolTip(cancelButton, text=_("Close this dialog. "), wraplength=240)

        frame.grid(row=0, column=0, sticky=(N, S, E, W))
        frame.columnconfigure(1, weight=3)
        frame.columnconfigure(2, weight=1)
        window = self.winfo_toplevel()
        window.columnconfigure(0, weight=1)
        self.geometry("+{0}+{1}".format(dialogX + 150, dialogY + 100))

        #self.bind("<Return>", self.ok)
        #self.bind("<Escape>", self.close)

        self.protocol("WM_DELETE_WINDOW", self.close)
        self.grab_set()

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