def __init__(self, modelManager):
     self.modelManager = modelManager
     self.urls = [os.path.join(modelManager.cntlr.configDir, "disclosuresystems.xml")]
     # get custom config xml file url
     for pluginXbrlMethod in pluginClassMethods("DisclosureSystem.ConfigURL"):
         self.urls.append(pluginXbrlMethod(self))
     # get custom disclosure system (type name, test variable)
     self.pluginDisclosureTypes = {}  # dict of type name, test variable name
     for pluginXbrlMethod in pluginClassMethods("DisclosureSystem.Types"):
         for typeName, typeTestVariable in pluginXbrlMethod(self):
             self.pluginDisclosureTypes[typeName] = typeTestVariable
     self.clear()
Exemple #2
0
def saveTargetDocument(filing, modelXbrl, targetDocumentFilename, targetDocumentSchemaRefs,
                       outputZip=None, filingFiles=None,
                       suffix=DEFAULT_DISTINGUISHING_SUFFIX, iext=DEFAULT_INSTANCE_EXT):
    sourceDir = os.path.dirname(modelXbrl.modelDocument.filepath)
    def addLocallyReferencedFile(elt,filingFiles):
        if elt.tag in ("a", "img"):
            for attrTag, attrValue in elt.items():
                if attrTag in ("href", "src") and not isHttpUrl(attrValue) and not os.path.isabs(attrValue):
                    attrValue = attrValue.partition('#')[0] # remove anchor
                    if attrValue: # ignore anchor references to base document
                        attrValue = os.path.normpath(attrValue) # change url path separators to host separators
                        file = os.path.join(sourceDir,attrValue)
                        if modelXbrl.fileSource.isInArchive(file, checkExistence=True) or modelXbrl.fileSource.exists(file):
                            filingFiles.add(file)
    targetUrlParts = targetDocumentFilename.rpartition(".")
    targetUrl = targetUrlParts[0] + suffix + targetUrlParts[2]
    modelXbrl.modelManager.showStatus(_("Extracting instance ") + os.path.basename(targetUrl))
    for pluginXbrlMethod in pluginClassMethods("InlineDocumentSet.CreateTargetInstance"):
        targetInstance = pluginXbrlMethod(modelXbrl, targetUrl, targetDocumentSchemaRefs, filingFiles,
                                          # no lang on xbrl:xbrl, specific xml:lang on elements which aren't en-US
                                          baseXmlLang=None, defaultXmlLang="en-US")
        if outputZip:
            targetInstance.saveInstance(overrideFilepath=targetUrl, outputZip=outputZip, updateFileHistory=False, xmlcharrefreplace=True)
        else:
            fh = io.StringIO();
            targetInstance.saveInstance(overrideFilepath=targetUrl, outputFile=fh, updateFileHistory=False, xmlcharrefreplace=True)
            fh.seek(0)
            filing.writeFile(targetUrl, fh.read())
            fh.close()
        if getattr(modelXbrl, "isTestcaseVariation", False):
            modelXbrl.extractedInlineInstance = True # for validation comparison
        modelXbrl.modelManager.showStatus(_("Saved extracted instance"), clearAfter=5000)
        return # there can only be one "InlineDocumentSet.CreateTargetInstance" but just to be sure 
    cntlr.logTrace(_("Unable to save extracted document, missing plugin class \"InlineDocumentSet.CreateTargetInstance\"."))
 def load(self, filesource, nextaction=None):
     """Load an entry point modelDocument object(s), which in turn load documents they discover 
     (for the case of instance, taxonomies, and versioning reports), but defer loading instances 
     for test case and RSS feeds.  
     
     The modelXbrl that is loaded is 'stacked', by this class, so that any modelXbrl operations such as validate, 
     and close, operate on the most recently loaded modelXbrl, and compareDTSes operates on the two 
     most recently loaded modelXbrl's.
     
     :param filesource: may be a FileSource object, with the entry point selected, or string file name (or web URL). 
     :type filesource: FileSource or str
     :param nextAction: status line text string, if any, to show upon completion
     :type nextAction: str
     """
     try:
         if filesource.url.startswith("urn:uuid:"): # request for an open modelXbrl
             for modelXbrl in self.loadedModelXbrls:
                 if not modelXbrl.isClosed and modelXbrl.uuid == filesource.url:
                     return modelXbrl
             raise IOError(_("Open file handle is not open: {0}").format(filesource.url))
     except AttributeError:
         pass # filesource may be a string, which has no url attribute
     self.filesource = filesource
     modelXbrl = None # loaded modelXbrl
     for customLoader in pluginClassMethods("ModelManager.Load"):
         modelXbrl = customLoader(self, filesource)
         if modelXbrl is not None:
             break # custom loader did the loading
     if modelXbrl is None:  # use default xbrl loader
         modelXbrl = ModelXbrl.load(self, filesource, nextaction)
     self.modelXbrl = modelXbrl
     self.loadedModelXbrls.append(self.modelXbrl)
     return self.modelXbrl
Exemple #4
0
def initUI(testObject):
    testObject.saveReferences = False # <- set this to create new references
    testObject.referencesDir = None
    testObject.cntlrWinMain = None
    testObject.process = psutil.Process(os.getpid())
    testObject.entryPointInfos = None
    testObject.maxSize = 0
    testObject.prevMemConsumed = 0
    testObject.testContext = None
    testObject.viewHelper = None
    
    testObject.application = Tk()
    testObject.cntlrWinMain = CntlrWinMain(testObject.application)
    testObject.application.protocol("WM_DELETE_WINDOW", testObject.cntlrWinMain.quit)
    
    testObject.testDir = getTestDir()
    testObject.referencesDir = testObject.testDir + "/references/"        
    
    testObject.cntlrWinMain.setTestMode(True)
    # make sure we use a plugin loaded by the plugin manager!!
    for pluginMethod in pluginClassMethods("DevTesting.GetTestContext"):
        testObject.testContext = pluginMethod()
        break
    testObject.testContext.recordTableLayout = True
    testObject.testContext.saveFilePath = testObject.testDir + "/tmp/a1.xbrl"        
 def resetProxies(self, httpProxyTuple):
     # for ntlm user and password are required
     self.hasNTLM = False
     if isinstance(httpProxyTuple,(tuple,list)) and len(httpProxyTuple) == 5:
         useOsProxy, _urlAddr, _urlPort, user, password = httpProxyTuple
         _proxyDirFmt = proxyDirFmt(httpProxyTuple)
         # only try ntlm if user and password are provided because passman is needed
         if user and not useOsProxy:
             for pluginXbrlMethod in pluginClassMethods("Proxy.HTTPNtlmAuthHandler"):
                 HTTPNtlmAuthHandler = pluginXbrlMethod()
                 if HTTPNtlmAuthHandler is not None:
                     self.hasNTLM = True
             if not self.hasNTLM: # try for python site-packages ntlm
                 try:
                     from ntlm import HTTPNtlmAuthHandler
                     self.hasNTLM = True
                 except ImportError:
                     pass
         if self.hasNTLM:    
             pwrdmgr = proxyhandlers.HTTPPasswordMgrWithDefaultRealm()
             pwrdmgr.add_password(None, _proxyDirFmt["http"], user, password)                
             self.proxy_handler = proxyhandlers.ProxyHandler({})
             self.proxy_auth_handler = proxyhandlers.ProxyBasicAuthHandler(pwrdmgr)
             self.http_auth_handler = proxyhandlers.HTTPBasicAuthHandler(pwrdmgr)
             self.ntlm_auth_handler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(pwrdmgr)            
             self.opener = proxyhandlers.build_opener(self.proxy_handler, self.ntlm_auth_handler, self.proxy_auth_handler, self.http_auth_handler)
     if not self.hasNTLM:
         self.proxy_handler = proxyhandlers.ProxyHandler(proxyDirFmt(httpProxyTuple))
         self.proxy_auth_handler = proxyhandlers.ProxyBasicAuthHandler()
         self.http_auth_handler = proxyhandlers.HTTPBasicAuthHandler()
         self.opener = proxyhandlers.build_opener(self.proxy_handler, self.proxy_auth_handler, self.http_auth_handler)
Exemple #6
0
def testcaseVariationXbrlLoaded(testcaseModelXbrl, instanceModelXbrl, modelTestcaseVariation, *args, **kwargs):
    # Validate of RSS feed item or testcase variation (simulates filing & cmd line load events
    modelManager = instanceModelXbrl.modelManager
    if (hasattr(testcaseModelXbrl, "efmOptions") and 
        modelManager.validateDisclosureSystem and getattr(modelManager.disclosureSystem, "EFMplugin", False) and 
        (instanceModelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE or 
        instanceModelXbrl.modelDocument.type == ModelDocument.Type.INLINEXBRL)):
        cntlr = modelManager.cntlr
        options = testcaseModelXbrl.efmOptions
        entrypointFiles = [{"file":instanceModelXbrl.modelDocument.uri}]
        if not hasattr(modelManager, "efmFiling"): # first instance of filing
            modelManager.efmFiling = Filing(cntlr, options, instanceModelXbrl.fileSource, entrypointFiles, None, None, instanceModelXbrl.errorCaptureLevel)
            # this event is called for filings (of instances) as well as test cases, for test case it just keeps options accessible
            for pluginXbrlMethod in pluginClassMethods("EdgarRenderer.Filing.Start"):
                pluginXbrlMethod(cntlr, options, entrypointFiles, modelManager.efmFiling)
        modelManager.efmFiling.addReport(instanceModelXbrl)
        _report = modelManager.efmFiling.reports[-1]
        _report.entryPoint = entrypointFiles[0]
        modelManager.efmFiling.arelleUnitTests = instanceModelXbrl.arelleUnitTests.copy() # allow unit tests to be used after instance processing finished
        # check for parameters on instance
        for _instanceElt in XmlUtil.descendants(modelTestcaseVariation, "*", "instance", "readMeFirst", "true", False):
            if instanceModelXbrl.modelDocument.uri.endswith(_instanceElt.text):
                if _instanceElt.get("exhibitType"):
                    _report.entryPoint["exhibitType"] = _report.exhibitType = _instanceElt.get("exhibitType")
                break
Exemple #7
0
 def test(self):
     testDir = os.path.dirname(os.path.abspath(sys.modules[__name__].__file__))
     testFileSmall = testDir + "/solvency/2.0/random/spv_20_instance.xbrl"
     application = Tk()
     cntlrWinMain = CntlrWinMain(application)
     application.protocol("WM_DELETE_WINDOW", cntlrWinMain.quit)
     
     cntlrWinMain.setTestMode(True)
     for pluginMethod in pluginClassMethods("DevTesting.GetTestContext"):
         testContext = pluginMethod()
         break
     testContext.checkMemoryOnClose = True
     testContext.dumpFilePrefix = testDir + "/tmp/dump_"
     
     tr = tracker.SummaryTracker()
     
     for idx in range(4):
         print("\nIteration " + str(idx))
         cntlrWinMain.fileOpenFile(testFileSmall)
         cntlrWinMain.logClear()
         cntlrWinMain.fileClose()    
         
         tr.print_diff()  
         if idx > 1:
             assert testContext.diffNumObjects < 8000, "Check for new objects leak"  
 def validateRssFeed(self):
     self.modelXbrl.info("info", "RSS Feed", modelDocument=self.modelXbrl)
     from arelle.FileSource import openFileSource
     for rssItem in self.modelXbrl.modelDocument.rssItems:
         self.modelXbrl.info("info", _("RSS Item %(accessionNumber)s %(formType)s %(companyName)s %(period)s"),
             modelObject=rssItem, accessionNumber=rssItem.accessionNumber, formType=rssItem.formType, companyName=rssItem.companyName, period=rssItem.period)
         modelXbrl = None
         try:
             modelXbrl = ModelXbrl.load(self.modelXbrl.modelManager, 
                                        openFileSource(rssItem.zippedUrl, self.modelXbrl.modelManager.cntlr),
                                        _("validating"))
             self.instValidator.validate(modelXbrl, self.modelXbrl.modelManager.formulaOptions.typedParameters())
             self.instValidator.close()
             rssItem.setResults(modelXbrl)
             self.modelXbrl.modelManager.viewModelObject(self.modelXbrl, rssItem.objectId())
             for pluginXbrlMethod in pluginClassMethods("Validate.RssItem"):
                 pluginXbrlMethod(self, modelXbrl, rssItem)
             modelXbrl.close()
         except Exception as err:
             self.modelXbrl.error("exception",
                 _("RSS item validation exception: %(error)s, instance: %(instance)s"),
                 modelXbrl=(self.modelXbrl, modelXbrl),
                 instance=rssItem.zippedUrl, error=err,
                 exc_info=True)
             try:
                 self.instValidator.close()
                 if modelXbrl is not None:
                     modelXbrl.close()
             except Exception as err:
                 pass
         del modelXbrl  # completely dereference
Exemple #9
0
 def clear(self):
     self.selection = None
     self.standardTaxonomiesDict = {}
     self.familyHrefs = {}
     self.standardLocalHrefs = set()
     self.standardAuthorities = set()
     self.baseTaxonomyNamespaces = set()
     self.standardPrefixes = {}
     self.names = []
     self.name = None
     self.validationType = None
     self.exclusiveTypesPattern = None # regex of type matches exclusive with validationType
     # previoulsy built-in types (intent to replace with plugin defined types)
     self.EFM = False
     self.GFM = False
     self.EFMorGFM = False
     self.HMRC = False
     self.SBRNL = False
     self.pluginTypes = set()
     for pluginXbrlMethod in pluginClassMethods("DisclosureSystem.Types"):
         for typeName, typeTestVariable in pluginXbrlMethod(self):
             setattr(self, typeTestVariable, False)
             self.pluginTypes.add(typeName)
     self.validateFileText = False
     self.allowedExternalHrefPattern = None
     self.schemaValidateSchema = None
     self.blockDisallowedReferences = False
     self.maxSubmissionSubdirectoryEntryNesting = 0
     self.defaultXmlLang = None
     self.defaultXmlEncoding = "utf-8"
     self.xmlLangPattern = None
     self.defaultLanguage = None
     self.language = None
     self.standardTaxonomiesUrl = None
     self.mappingsUrl = os.path.join(self.modelManager.cntlr.configDir, "mappings.xml")
     self.mappedFiles = {}
     self.mappedPaths = []
     self.utrUrl = "http://www.xbrl.org/utr/utr.xml"
     self.utrTypeEntries = None
     self.identifierSchemePattern = None
     self.identifierValuePattern = None
     self.identifierValueName = None
     self.contextElement = None
     self.roleDefinitionPattern = None
     self.labelCheckPattern = None
     self.labelTrimPattern = None
     self.deiNamespacePattern = None
     self.deiAmendmentFlagElement = None
     self.deiCurrentFiscalYearEndDateElement = None
     self.deiDocumentFiscalYearFocusElement = None
     self.deiDocumentPeriodEndDateElement = None
     self.deiFilerIdentifierElement = None
     self.deiFilerNameElement = None
     self.logLevelFilter = None
     self.logCodeFilter = None
     self.standardTaxonomyDatabase = None
     self.standardTaxonomyUrlPattern = None
     self.version = (0,0,0)
Exemple #10
0
def testcaseVariationXbrlValidated(testcaseModelXbrl, instanceModelXbrl, *args, **kwargs): 
    modelManager = instanceModelXbrl.modelManager
    if (hasattr(modelManager, "efmFiling") and 
        (instanceModelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE or 
        instanceModelXbrl.modelDocument.type == ModelDocument.Type.INLINEXBRL)):
        efmFiling = modelManager.efmFiling
        _report = modelManager.efmFiling.reports[-1]
        for pluginXbrlMethod in pluginClassMethods("EdgarRenderer.Xbrl.Run"):
            pluginXbrlMethod(modelManager.cntlr, efmFiling.options, instanceModelXbrl, efmFiling, _report)
 def readMeFirstUris(self):
     try:
         return self._readMeFirstUris
     except AttributeError:
         self._readMeFirstUris = []
         # first look if any plugin method to get readme first URIs
         if not any(
                 pluginXbrlMethod(self)
                 for pluginXbrlMethod in pluginClassMethods(
                     "ModelTestcaseVariation.ReadMeFirstUris")):
             if self.localName == "testGroup":  #w3c testcase
                 instanceTestElement = XmlUtil.descendant(
                     self, None, "instanceTest")
                 if instanceTestElement is not None:  # take instance first
                     self._readMeFirstUris.append(
                         XmlUtil.descendantAttr(
                             instanceTestElement, None, "instanceDocument",
                             "{http://www.w3.org/1999/xlink}href"))
                 else:
                     schemaTestElement = XmlUtil.descendant(
                         self, None, "schemaTest")
                     if schemaTestElement is not None:
                         self._readMeFirstUris.append(
                             XmlUtil.descendantAttr(
                                 schemaTestElement, None, "schemaDocument",
                                 "{http://www.w3.org/1999/xlink}href"))
             elif self.localName == "test-case":  #xpath testcase
                 inputFileElement = XmlUtil.descendant(
                     self, None, "input-file")
                 if inputFileElement is not None:  # take instance first
                     self._readMeFirstUris.append(
                         "TestSources/" + inputFileElement.text + ".xml")
             else:
                 # default built-in method for readme first uris
                 for anElement in self.iterdescendants():
                     if isinstance(anElement,
                                   ModelObject) and anElement.get(
                                       "readMeFirst") == "true":
                         if anElement.get(
                                 "{http://www.w3.org/1999/xlink}href"):
                             uri = anElement.get(
                                 "{http://www.w3.org/1999/xlink}href")
                         else:
                             uri = XmlUtil.innerText(anElement)
                         if anElement.get("name"):
                             self._readMeFirstUris.append((ModelValue.qname(
                                 anElement, anElement.get("name")), uri))
                         elif anElement.get("dts"):
                             self._readMeFirstUris.append(
                                 (anElement.get("dts"), uri))
                         else:
                             self._readMeFirstUris.append(uri)
         if not self._readMeFirstUris:  # provide a dummy empty instance document
             self._readMeFirstUris.append(
                 os.path.join(self.modelXbrl.modelManager.cntlr.configDir,
                              "empty-instance.xml"))
         return self._readMeFirstUris
Exemple #12
0
def filingStart(cntlr, options, filesource, entrypointFiles, sourceZipStream=None, responseZipStream=None, *args, **kwargs):
    modelManager = cntlr.modelManager
    # cntlr.addToLog("TRACE EFM filing start val={} plugin={}".format(modelManager.validateDisclosureSystem, getattr(modelManager.disclosureSystem, "EFMplugin", False)))
    if modelManager.validateDisclosureSystem and getattr(modelManager.disclosureSystem, "EFMplugin", False):
        # cntlr.addToLog("TRACE EFM filing start 2 classes={} moduleInfos={}".format(pluginMethodsForClasses, modulePluginInfos))
        modelManager.efmFiling = Filing(cntlr, options, filesource, entrypointFiles, sourceZipStream, responseZipStream)
        # this event is called for filings (of instances) as well as test cases, for test case it just keeps options accessible
        for pluginXbrlMethod in pluginClassMethods("EdgarRenderer.Filing.Start"):
            pluginXbrlMethod(cntlr, options, entrypointFiles, modelManager.efmFiling)
Exemple #13
0
 def resultXbrlInstanceUri(self):
     for pluginXbrlMethod in pluginClassMethods("ModelTestcaseVariation.ResultXbrlInstanceUri"):
         resultInstanceUri = pluginXbrlMethod(self)
         if resultInstanceUri is not None:
             return resultInstanceUri or None # (empty string returns None)
         
     resultInstance = XmlUtil.descendant(XmlUtil.descendant(self, None, "result"), None, "instance")
     if resultInstance is not None:
         return XmlUtil.text(resultInstance)
     return None
 def severityLevel(self):
     for pluginXbrlMethod in pluginClassMethods("ModelTestcaseVariation.ExpectedSeverity"):
         severityLevelName = pluginXbrlMethod(self)
         if severityLevelName: # ignore plug in if not a plug-in-recognized test case
             return logging._checkLevel(severityLevelName)
     # default behavior without plugins
     # SEC error cases have <assert severity={err|wrn}>...
     if XmlUtil.descendant(self, None, "assert", attrName="severity", attrValue="wrn") is not None:
         return logging._checkLevel("WARNING")
     return logging._checkLevel("INCONSISTENCY")
Exemple #15
0
def xbrlRun(cntlr, options, modelXbrl, *args, **kwargs):
    # cntlr.addToLog("TRACE EFM xbrl run")
    modelManager = cntlr.modelManager
    if (hasattr(modelManager, "efmFiling") and
        (modelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE or 
        modelXbrl.modelDocument.type == ModelDocument.Type.INLINEXBRL)):
        efmFiling = modelManager.efmFiling
        _report = efmFiling.reports[-1]
        if True: # HF TESTING: not (options.abortOnMajorError and len(modelXbrl.errors) > 0):
            for pluginXbrlMethod in pluginClassMethods("EdgarRenderer.Xbrl.Run"):
                pluginXbrlMethod(cntlr, options, modelXbrl, modelManager.efmFiling, _report)
Exemple #16
0
 def validateRssFeed(self):
     self.modelXbrl.info("info", "RSS Feed", modelDocument=self.modelXbrl)
     from arelle.FileSource import openFileSource
     reloadCache = getattr(self.modelXbrl, "reloadCache", False)
     for rssItem in self.modelXbrl.modelDocument.rssItems:
         if getattr(rssItem, "skipRssItem", False):
             self.modelXbrl.info("info", _("skipping RSS Item %(accessionNumber)s %(formType)s %(companyName)s %(period)s"),
                 modelObject=rssItem, accessionNumber=rssItem.accessionNumber, formType=rssItem.formType, companyName=rssItem.companyName, period=rssItem.period)
             continue
         self.modelXbrl.info("info", _("RSS Item %(accessionNumber)s %(formType)s %(companyName)s %(period)s"),
             modelObject=rssItem, accessionNumber=rssItem.accessionNumber, formType=rssItem.formType, companyName=rssItem.companyName, period=rssItem.period)
         modelXbrl = None
         try:
             modelXbrl = ModelXbrl.load(self.modelXbrl.modelManager, 
                                        openFileSource(rssItem.zippedUrl, self.modelXbrl.modelManager.cntlr, reloadCache=reloadCache),
                                        _("validating"), rssItem=rssItem)
             for pluginXbrlMethod in pluginClassMethods("RssItem.Xbrl.Loaded"):  
                 pluginXbrlMethod(modelXbrl, {}, rssItem)      
             if getattr(rssItem, "doNotProcessRSSitem", False) or modelXbrl.modelDocument is None:
                 modelXbrl.close()
                 continue # skip entry based on processing criteria
             self.instValidator.validate(modelXbrl, self.modelXbrl.modelManager.formulaOptions.typedParameters(self.modelXbrl.prefixedNamespaces))
             self.instValidator.close()
             rssItem.setResults(modelXbrl)
             self.modelXbrl.modelManager.viewModelObject(self.modelXbrl, rssItem.objectId())
             for pluginXbrlMethod in pluginClassMethods("Validate.RssItem"):
                 pluginXbrlMethod(self, modelXbrl, rssItem)
             modelXbrl.close()
         except Exception as err:
             self.modelXbrl.error("exception:" + type(err).__name__,
                 _("RSS item validation exception: %(error)s, instance: %(instance)s"),
                 modelXbrl=(self.modelXbrl, modelXbrl),
                 instance=rssItem.zippedUrl, error=err,
                 exc_info=True)
             try:
                 self.instValidator.close()
                 if modelXbrl is not None:
                     modelXbrl.close()
             except Exception as err:
                 pass
         del modelXbrl  # completely dereference
Exemple #17
0
def filingEnd(cntlr, options, filesource, entrypointFiles, sourceZipStream=None, responseZipStream=None, *args, **kwargs):
    #cntlr.addToLog("TRACE EFM filing end")
    modelManager = cntlr.modelManager
    if hasattr(modelManager, "efmFiling"):
        for pluginXbrlMethod in pluginClassMethods("EdgarRenderer.Filing.End"):
            pluginXbrlMethod(cntlr, options, filesource, modelManager.efmFiling)
        #cntlr.addToLog("TRACE EdgarRenderer end")
        # save JSON file of instances and referenced documents
        filingReferences = dict((report.url, report)
                                for report in modelManager.efmFiling.reports)

        modelManager.efmFiling.close()
        del modelManager.efmFiling
def commandLineXbrlRun(cntlr, options, modelXbrl, *args, **kwargs):
    # skip if another class handles saving (e.g., EdgarRenderer)
    for pluginXbrlMethod in pluginClassMethods('InlineDocumentSet.SavesTargetInstance'):
        if pluginXbrlMethod():
            return # saving of target instance is handled by another class
    # extend XBRL-loaded run processing for this option
    if getattr(options, "saveTargetInstance", False) or getattr(options, "saveTargetFiling", False):
        if cntlr.modelManager is None or cntlr.modelManager.modelXbrl is None or (   
            cntlr.modelManager.modelXbrl.modelDocument.type not in (Type.INLINEXBRL, Type.INLINEXBRLDOCUMENTSET)):
            cntlr.addToLog("No inline XBRL document or manifest loaded.")
            return
        runSaveTargetDocumentMenuCommand(cntlr, 
                                         runInBackground=False,
                                         saveTargetFiling=getattr(options, "saveTargetFiling", False))
Exemple #19
0
 def expected(self):
     for pluginXbrlMethod in pluginClassMethods("ModelTestcaseVariation.ExpectedResult"):
         expected = pluginXbrlMethod(self)
         if expected:
             return expected
     # default behavior without plugins
     if self.localName == "testcase":
         return self.document.basename[:4]   #starts with PASS or FAIL
     elif self.localName == "testGroup":  #w3c testcase
         instanceTestElement = XmlUtil.descendant(self, None, "instanceTest")
         if instanceTestElement is not None: # take instance first
             return XmlUtil.descendantAttr(instanceTestElement, None, "expected", "validity")
         else:
             schemaTestElement = XmlUtil.descendant(self, None, "schemaTest")
             if schemaTestElement is not None:
                 return XmlUtil.descendantAttr(schemaTestElement, None, "expected", "validity")
     resultElement = XmlUtil.descendant(self, None, "result")
     if resultElement is not None:
         expected = resultElement.get("expected")
         if expected and resultElement.get("nonStandardErrorCodes") == "true":
             # if @expected and @nonStandardErrorCodes then use expected instead of error codes
             return expected
     errorElement = XmlUtil.descendant(self, None, "error")
     resultElement = XmlUtil.descendant(self, None, "result")
     if errorElement is not None and not errorElement.get("nonStandardErrorCodes"):
         _errorText = XmlUtil.text(errorElement)
         if ' ' in _errorText: # list of tokens
             return _errorText
         return ModelValue.qname(errorElement, _errorText)  # turn into a QName
     if resultElement is not None:
         if expected:
             return expected
         for assertElement in XmlUtil.children(resultElement, None, "assert"):
             num = assertElement.get("num")
             if num == "99999": # inline test, use name as expected
                 return assertElement.get("name")
             if len(num) == 5:
                 return "EFM.{0}.{1}.{2}".format(num[0],num[1:3],num[3:6])
         asserTests = {}
         for atElt in XmlUtil.children(resultElement, None, "assertionTests"):
             try:
                 asserTests[atElt.get("assertionID")] = (_INT(atElt.get("countSatisfied")),_INT(atElt.get("countNotSatisfied")))
             except ValueError:
                 pass
         if asserTests:
             return asserTests
     elif self.get("result"):
         return self.get("result")
             
     return None
def runSaveTargetDocumentMenuCommand(cntlr, runInBackground=False, saveTargetFiling=False):
    # skip if another class handles saving (e.g., EdgarRenderer)
    for pluginXbrlMethod in pluginClassMethods('InlineDocumentSet.SavesTargetInstance'):
        if pluginXbrlMethod():
            return # saving of target instance is handled by another class
    # save DTS menu item has been invoked
    if (cntlr.modelManager is None or 
        cntlr.modelManager.modelXbrl is None or 
        cntlr.modelManager.modelXbrl.modelDocument.type not in (Type.INLINEXBRL, Type.INLINEXBRLDOCUMENTSET)):
        cntlr.addToLog("No inline XBRL document set loaded.")
        return
    modelDocument = cntlr.modelManager.modelXbrl.modelDocument
    if modelDocument.type == Type.INLINEXBRLDOCUMENTSET:
        targetFilename = modelDocument.targetDocumentPreferredFilename
        targetSchemaRefs = modelDocument.targetDocumentSchemaRefs
    else:
        filepath, fileext = os.path.splitext(modelDocument.filepath)
        if fileext not in (".xml", ".xbrl"):
            fileext = ".xbrl"
        targetFilename = filepath + fileext
        targetSchemaRefs = set(modelDocument.relativeUri(referencedDoc.uri)
                               for referencedDoc in modelDocument.referencesDocument.keys()
                               if referencedDoc.type == Type.SCHEMA)
    if runInBackground:
        import threading
        thread = threading.Thread(target=lambda _x = modelDocument.modelXbrl, _f = targetFilename, _s = targetSchemaRefs:
                                        saveTargetDocument(_x, _f, _s))
        thread.daemon = True
        thread.start()
    else:
        if saveTargetFiling:
            targetFilename = os.path.basename(targetFilename)
            filingZip = zipfile.ZipFile(saveTargetFiling, 'w', zipfile.ZIP_DEFLATED, True)
            filingFiles = set()
            # copy referencedDocs to two levels
            def addRefDocs(doc):
                for refDoc in doc.referencesDocument.keys():
                    if refDoc.uri not in filingFiles:
                        filingFiles.add(refDoc.uri)
                        addRefDocs(refDoc)
            addRefDocs(modelDocument)
        else:
            filingZip = None
            filingFiles = None
        saveTargetDocument(modelDocument.modelXbrl, targetFilename, targetSchemaRefs, filingZip, filingFiles)
        if saveTargetFiling:
            instDir = os.path.dirname(modelDocument.uri.split(IXDS_DOC_SEPARATOR)[0])
            for refFile in filingFiles:
                if refFile.startswith(instDir):
                    filingZip.write(refFile, modelDocument.relativeUri(refFile))
 def expected(self):
     for pluginXbrlMethod in pluginClassMethods("ModelTestcaseVariation.ExpectedResult"):
         expected = pluginXbrlMethod(self)
         if expected:
             return expected
     # default behavior without plugins
     if self.localName == "testcase":
         return self.document.basename[:4]   #starts with PASS or FAIL
     elif self.localName == "testGroup":  #w3c testcase
         instanceTestElement = XmlUtil.descendant(self, None, "instanceTest")
         if instanceTestElement is not None: # take instance first
             return XmlUtil.descendantAttr(instanceTestElement, None, "expected", "validity")
         else:
             schemaTestElement = XmlUtil.descendant(self, None, "schemaTest")
             if schemaTestElement is not None:
                 return XmlUtil.descendantAttr(schemaTestElement, None, "expected", "validity")
     resultElement = XmlUtil.descendant(self, None, "result")
     if resultElement is not None:
         expected = resultElement.get("expected")
         if expected and resultElement.get("nonStandardErrorCodes") == "true":
             # if @expected and @nonStandardErrorCodes then use expected instead of error codes
             return expected
     errorElement = XmlUtil.descendant(self, None, "error")
     if errorElement is not None:
         _errorText = XmlUtil.text(errorElement)
         if ' ' in _errorText: # list of tokens
             return _errorText
         return ModelValue.qname(errorElement, _errorText)  # turn into a QName
     if resultElement is not None:
         if expected:
             return expected
         for assertElement in XmlUtil.children(resultElement, None, "assert"):
             num = assertElement.get("num")
             if num == "99999": # inline test, use name as expected
                 return assertElement.get("name")
             if len(num) == 5:
                 return "EFM.{0}.{1}.{2}".format(num[0],num[1:3],num[3:6])
         asserTests = {}
         for atElt in XmlUtil.children(resultElement, None, "assertionTests"):
             try:
                 asserTests[atElt.get("assertionID")] = (_INT(atElt.get("countSatisfied")),_INT(atElt.get("countNotSatisfied")))
             except ValueError:
                 pass
         if asserTests:
             return asserTests
     elif self.get("result"):
         return self.get("result")
             
     return None
 def severityLevel(self):
     for pluginXbrlMethod in pluginClassMethods(
             "ModelTestcaseVariation.ExpectedSeverity"):
         severityLevelName = pluginXbrlMethod(self)
         if severityLevelName:  # ignore plug in if not a plug-in-recognized test case
             return logging._checkLevel(severityLevelName)
     # default behavior without plugins
     # SEC error cases have <assert severity={err|wrn}>...
     if XmlUtil.descendant(self,
                           None,
                           "assert",
                           attrName="severity",
                           attrValue="wrn") is not None:
         return logging._checkLevel("WARNING")
     return logging._checkLevel("INCONSISTENCY")
def commandLineXbrlRun(cntlr, options, modelXbrl, *args, **kwargs):
    # skip if another class handles saving (e.g., EdgarRenderer)
    for pluginXbrlMethod in pluginClassMethods('InlineDocumentSet.SavesTargetInstance'):
        if pluginXbrlMethod():
            return # saving of target instance is handled by another class
    # extend XBRL-loaded run processing for this option
    if getattr(options, "saveTargetInstance", False) or getattr(options, "saveTargetFiling", False):
        if cntlr.modelManager is None or cntlr.modelManager.modelXbrl is None or (   
            cntlr.modelManager.modelXbrl.modelDocument.type not in (Type.INLINEXBRL, Type.INLINEXBRLDOCUMENTSET)):
            cntlr.addToLog("No inline XBRL document or manifest loaded.")
            return
        runSaveTargetDocumentMenuCommand(cntlr, 
                                         runInBackground=False,
                                         saveTargetFiling=getattr(options, "saveTargetFiling", False),
                                         encodeSavedXmlChars=getattr(options, "encodeSavedXmlChars", False))
Exemple #24
0
 def load(self,
          filesource,
          nextaction=None,
          taxonomyPackages=None,
          **kwargs):
     """Load an entry point modelDocument object(s), which in turn load documents they discover 
     (for the case of instance, taxonomies, and versioning reports), but defer loading instances 
     for test case and RSS feeds.  
     
     The modelXbrl that is loaded is 'stacked', by this class, so that any modelXbrl operations such as validate, 
     and close, operate on the most recently loaded modelXbrl, and compareDTSes operates on the two 
     most recently loaded modelXbrl's.
     
     :param filesource: may be a FileSource object, with the entry point selected, or string file name (or web URL). 
     :type filesource: FileSource or str
     :param nextAction: status line text string, if any, to show upon completion
     :type nextAction: str
     :param taxonomyPackages: array of URLs of taxonomy packages required for load operation
     """
     if taxonomyPackages:
         resetPackageMappings = False
         for pkgUrl in taxonomyPackages:
             if PackageManager.addPackage(self.cntlr, pkgUrl):
                 resetPackageMappings = True
         if resetPackageMappings:
             PackageManager.rebuildRemappings(self.cntlr)
     try:
         if filesource.url.startswith(
                 "urn:uuid:"):  # request for an open modelXbrl
             for modelXbrl in self.loadedModelXbrls:
                 if not modelXbrl.isClosed and modelXbrl.uuid == filesource.url:
                     return modelXbrl
             raise IOError(
                 _("Open file handle is not open: {0}").format(
                     filesource.url))
     except AttributeError:
         pass  # filesource may be a string, which has no url attribute
     self.filesource = filesource
     modelXbrl = None  # loaded modelXbrl
     for customLoader in pluginClassMethods("ModelManager.Load"):
         modelXbrl = customLoader(self, filesource)
         if modelXbrl is not None:
             break  # custom loader did the loading
     if modelXbrl is None:  # use default xbrl loader
         modelXbrl = ModelXbrl.load(self, filesource, nextaction, **kwargs)
     self.modelXbrl = modelXbrl
     self.loadedModelXbrls.append(self.modelXbrl)
     return self.modelXbrl
Exemple #25
0
 def exists(self, filepath):
     archiveFileSource = self.fileSourceContainingFilepath(filepath)
     if archiveFileSource is not None:
         if filepath.startswith(archiveFileSource.basefile):
             archiveFileName = filepath[len(archiveFileSource.basefile) + 1:]
         else: # filepath.startswith(self.baseurl)
             archiveFileName = filepath[len(archiveFileSource.baseurl) + 1:]
         if (archiveFileSource.isZip or archiveFileSource.isTarGz or 
             archiveFileSource.isEis or archiveFileSource.isXfd or
             archiveFileSource.isRss or self.isInstalledTaxonomyPackage):
             return archiveFileName.replace("\\","/") in archiveFileSource.dir
     for pluginMethod in pluginClassMethods("FileSource.Exists"): #custom overrides for decription, etc
         existsResult = pluginMethod(self.cntlr, filepath)
         if existsResult is not None:
             return existsResult
     # assume it may be a plain ordinary file path
     return os.path.exists(filepath)
Exemple #26
0
def testcaseVariationXbrlLoaded(testcaseModelXbrl, instanceModelXbrl):
    # Validate of RSS feed item or testcase variation (simulates filing & cmd line load events
    modelManager = instanceModelXbrl.modelManager
    if (hasattr(testcaseModelXbrl, "efmOptions") and 
        modelManager.validateDisclosureSystem and getattr(modelManager.disclosureSystem, "EFMplugin", False) and 
        (instanceModelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE or 
        instanceModelXbrl.modelDocument.type == ModelDocument.Type.INLINEXBRL)):
        cntlr = modelManager.cntlr
        options = testcaseModelXbrl.efmOptions
        entrypointFiles = [{"file":instanceModelXbrl.modelDocument.uri}]
        modelManager.efmFiling = Filing(cntlr, options, instanceModelXbrl.fileSource, entrypointFiles, None, None)
        # this event is called for filings (of instances) as well as test cases, for test case it just keeps options accessible
        for pluginXbrlMethod in pluginClassMethods("EdgarRenderer.Filing.Start"):
            pluginXbrlMethod(cntlr, options, entrypointFiles, modelManager.efmFiling)
        modelManager.efmFiling.addReport(instanceModelXbrl)
        _report = modelManager.efmFiling.reports[-1]
        _report.entryPoint = entrypointFiles[0]
Exemple #27
0
 def exists(self, filepath):
     archiveFileSource = self.fileSourceContainingFilepath(filepath)
     if archiveFileSource is not None:
         if filepath.startswith(archiveFileSource.basefile):
             archiveFileName = filepath[len(archiveFileSource.basefile) + 1:]
         else: # filepath.startswith(self.baseurl)
             archiveFileName = filepath[len(archiveFileSource.baseurl) + 1:]
         if (archiveFileSource.isZip or archiveFileSource.isTarGz or 
             archiveFileSource.isEis or archiveFileSource.isXfd or
             archiveFileSource.isRss or self.isInstalledTaxonomyPackage):
             return archiveFileName.replace("\\","/") in archiveFileSource.dir
     for pluginMethod in pluginClassMethods("FileSource.Exists"): #custom overrides for decription, etc
         existsResult = pluginMethod(self.cntlr, filepath)
         if existsResult is not None:
             return existsResult
     # assume it may be a plain ordinary file path
     return os.path.exists(filepath)
Exemple #28
0
def saveTargetDocument(filing,
                       modelXbrl,
                       targetDocumentFilename,
                       targetDocumentSchemaRefs,
                       outputZip=None,
                       filingFiles=None,
                       suffix=DEFAULT_DISTINGUISHING_SUFFIX,
                       iext=DEFAULT_INSTANCE_EXT):
    sourceDir = os.path.dirname(modelXbrl.modelDocument.filepath)
    targetUrlParts = targetDocumentFilename.rpartition(".")
    targetUrl = targetUrlParts[0] + suffix + targetUrlParts[2]
    modelXbrl.modelManager.showStatus(
        _("Extracting instance ") + os.path.basename(targetUrl))
    for pluginXbrlMethod in pluginClassMethods(
            "InlineDocumentSet.CreateTargetInstance"):
        targetInstance = pluginXbrlMethod(
            modelXbrl,
            targetUrl,
            targetDocumentSchemaRefs,
            filingFiles,
            # no lang on xbrl:xbrl, specific xml:lang on elements which aren't en-US
            baseXmlLang=None,
            defaultXmlLang="en-US")
        if outputZip:
            targetInstance.saveInstance(overrideFilepath=targetUrl,
                                        outputZip=outputZip,
                                        updateFileHistory=False,
                                        xmlcharrefreplace=True)
        else:
            fh = io.StringIO()
            targetInstance.saveInstance(overrideFilepath=targetUrl,
                                        outputFile=fh,
                                        updateFileHistory=False,
                                        xmlcharrefreplace=True)
            fh.seek(0)
            filing.writeFile(targetUrl, fh.read())
            fh.close()
        if getattr(modelXbrl, "isTestcaseVariation", False):
            modelXbrl.extractedInlineInstance = True  # for validation comparison
        modelXbrl.modelManager.showStatus(_("Saved extracted instance"),
                                          clearAfter=5000)
        return  # there can only be one "InlineDocumentSet.CreateTargetInstance" but just to be sure
    cntlr.logTrace(
        _("Unable to save extracted document, missing plugin class \"InlineDocumentSet.CreateTargetInstance\"."
          ))
Exemple #29
0
def filingStart(cntlr,
                options,
                filesource,
                entrypointFiles,
                sourceZipStream=None,
                responseZipStream=None):
    modelManager = cntlr.modelManager
    # cntlr.addToLog("TRACE EFM filing start val={} plugin={}".format(modelManager.validateDisclosureSystem, getattr(modelManager.disclosureSystem, "EFMplugin", False)))
    if modelManager.validateDisclosureSystem and getattr(
            modelManager.disclosureSystem, "EFMplugin", False):
        # cntlr.addToLog("TRACE EFM filing start 2 classes={} moduleInfos={}".format(pluginMethodsForClasses, modulePluginInfos))
        modelManager.efmFiling = Filing(cntlr, options, filesource,
                                        entrypointFiles, sourceZipStream,
                                        responseZipStream)
        # this event is called for filings (of instances) as well as test cases, for test case it just keeps options accessible
        for pluginXbrlMethod in pluginClassMethods(
                "EdgarRenderer.Filing.Start"):
            pluginXbrlMethod(cntlr, options, entrypointFiles,
                             modelManager.efmFiling)
Exemple #30
0
def filingEnd(cntlr,
              options,
              filesource,
              entrypointFiles,
              sourceZipStream=None,
              responseZipStream=None):
    #cntlr.addToLog("TRACE EFM filing end")
    modelManager = cntlr.modelManager
    if hasattr(modelManager, "efmFiling"):
        for pluginXbrlMethod in pluginClassMethods("EdgarRenderer.Filing.End"):
            pluginXbrlMethod(cntlr, options, filesource,
                             modelManager.efmFiling)
        #cntlr.addToLog("TRACE EdgarRenderer end")
        # save JSON file of instances and referenced documents
        filingReferences = dict(
            (report.url, report) for report in modelManager.efmFiling.reports)

        modelManager.efmFiling.close()
        del modelManager.efmFiling
 def readMeFirstUris(self):
     try:
         return self._readMeFirstUris
     except AttributeError:
         self._readMeFirstUris = []
         # first look if any plugin method to get readme first URIs
         if not any(pluginXbrlMethod(self)
                    for pluginXbrlMethod in pluginClassMethods("ModelTestcaseVariation.ReadMeFirstUris")):
             if self.localName == "testGroup":  #w3c testcase
                 instanceTestElement = XmlUtil.descendant(self, None, "instanceTest")
                 if instanceTestElement is not None: # take instance first
                     self._readMeFirstUris.append(XmlUtil.descendantAttr(instanceTestElement, None, 
                                                                         "instanceDocument", 
                                                                         "{http://www.w3.org/1999/xlink}href"))
                 else:
                     schemaTestElement = XmlUtil.descendant(self, None, "schemaTest")
                     if schemaTestElement is not None:
                         self._readMeFirstUris.append(XmlUtil.descendantAttr(schemaTestElement, None, 
                                                                             "schemaDocument", 
                                                                             "{http://www.w3.org/1999/xlink}href"))
             elif self.localName == "test-case":  #xpath testcase
                 inputFileElement = XmlUtil.descendant(self, None, "input-file")
                 if inputFileElement is not None: # take instance first
                     self._readMeFirstUris.append("TestSources/" + inputFileElement.text + ".xml")
             elif self.resultIsTaxonomyPackage:
                 self._readMeFirstUris.append( os.path.join(self.modelDocument.filepathdir, "tests", self.get("name") + ".zip") )
             else:
                 # default built-in method for readme first uris
                 for anElement in self.iterdescendants():
                     if isinstance(anElement,ModelObject) and anElement.get("readMeFirst") == "true":
                         if anElement.get("{http://www.w3.org/1999/xlink}href"):
                             uri = anElement.get("{http://www.w3.org/1999/xlink}href")
                         else:
                             uri = XmlUtil.innerText(anElement)
                         if anElement.get("name"):
                             self._readMeFirstUris.append( (ModelValue.qname(anElement, anElement.get("name")), uri) )
                         elif anElement.get("dts"):
                             self._readMeFirstUris.append( (anElement.get("dts"), uri) )
                         else:
                             self._readMeFirstUris.append(uri)
         if not self._readMeFirstUris:  # provide a dummy empty instance document
             self._readMeFirstUris.append(os.path.join(self.modelXbrl.modelManager.cntlr.configDir, "empty-instance.xml"))
         return self._readMeFirstUris
Exemple #32
0
 def resetProxies(self, httpProxyTuple):
     # for ntlm user and password are required
     self.hasNTLM = False
     if isinstance(httpProxyTuple,
                   (tuple, list)) and len(httpProxyTuple) == 5:
         useOsProxy, _urlAddr, _urlPort, user, password = httpProxyTuple
         _proxyDirFmt = proxyDirFmt(httpProxyTuple)
         # only try ntlm if user and password are provided because passman is needed
         if user and not useOsProxy:
             for pluginXbrlMethod in pluginClassMethods(
                     "Proxy.HTTPNtlmAuthHandler"):
                 HTTPNtlmAuthHandler = pluginXbrlMethod()
                 if HTTPNtlmAuthHandler is not None:
                     self.hasNTLM = True
             if not self.hasNTLM:  # try for python site-packages ntlm
                 try:
                     from ntlm import HTTPNtlmAuthHandler
                     self.hasNTLM = True
                 except ImportError:
                     pass
         if self.hasNTLM:
             pwrdmgr = proxyhandlers.HTTPPasswordMgrWithDefaultRealm()
             pwrdmgr.add_password(None, _proxyDirFmt["http"], user,
                                  password)
             self.proxy_handler = proxyhandlers.ProxyHandler({})
             self.proxy_auth_handler = proxyhandlers.ProxyBasicAuthHandler(
                 pwrdmgr)
             self.http_auth_handler = proxyhandlers.HTTPBasicAuthHandler(
                 pwrdmgr)
             self.ntlm_auth_handler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(
                 pwrdmgr)
             self.opener = proxyhandlers.build_opener(
                 self.proxy_handler, self.ntlm_auth_handler,
                 self.proxy_auth_handler, self.http_auth_handler)
     if not self.hasNTLM:
         self.proxy_handler = proxyhandlers.ProxyHandler(
             proxyDirFmt(httpProxyTuple))
         self.proxy_auth_handler = proxyhandlers.ProxyBasicAuthHandler()
         self.http_auth_handler = proxyhandlers.HTTPBasicAuthHandler()
         self.opener = proxyhandlers.build_opener(self.proxy_handler,
                                                  self.proxy_auth_handler,
                                                  self.http_auth_handler)
Exemple #33
0
 def __init__(self, modelXbrl, inputXbrlInstance, sourceElement, inScopeVars=None):
     self.modelXbrl = modelXbrl
     self.isRunTimeExceeded = False
     self.inputXbrlInstance = inputXbrlInstance
     self.outputLastContext = {}   # last context element output per output instance
     self.outputLastUnit = {}
     self.outputLastFact = {}
     self.outputFirstFact = {}
     self.sourceElement = sourceElement
     self.contextItem = self.inputXbrlInstance.targetXbrlRootElement
     self.progHeader = None
     self.traceType = None
     self.variableSet = None
     self.inScopeVars = {} if inScopeVars is None else inScopeVars
     self.cachedFilterResults = {}
     if inputXbrlInstance: 
         self.inScopeVars[XbrlConst.qnStandardInputInstance] = inputXbrlInstance.modelXbrl
     self.customFunctions = {}
     for pluginXbrlMethod in pluginClassMethods("Formula.CustomFunctions"):
         self.customFunctions.update(pluginXbrlMethod())
Exemple #34
0
 def __init__(self, modelXbrl, inputXbrlInstance, sourceElement, inScopeVars=None):
     self.modelXbrl = modelXbrl
     self.isRunTimeExceeded = False
     self.inputXbrlInstance = inputXbrlInstance
     self.outputLastContext = {}   # last context element output per output instance
     self.outputLastUnit = {}
     self.outputLastFact = {}
     self.outputFirstFact = {}
     self.sourceElement = sourceElement
     self.contextItem = self.inputXbrlInstance.xmlRootElement
     self.progHeader = None
     self.traceType = None
     self.variableSet = None
     self.inScopeVars = {} if inScopeVars is None else inScopeVars
     self.cachedFilterResults = {}
     if inputXbrlInstance: 
         self.inScopeVars[XbrlConst.qnStandardInputInstance] = inputXbrlInstance.modelXbrl
     self.customFunctions = {}
     for pluginXbrlMethod in pluginClassMethods("Formula.CustomFunctions"):
         self.customFunctions.update(pluginXbrlMethod())
Exemple #35
0
 def __init__(self,
              cntlr,
              options=None,
              filesource=None,
              entrypointfiles=None,
              sourceZipStream=None,
              responseZipStream=None,
              errorCaptureLevel=None):
     self.cntlr = cntlr
     self.options = options
     self.filesource = filesource
     self.entrypointfiles = entrypointfiles
     self.sourceZipStream = sourceZipStream
     self.responseZipStream = responseZipStream
     self.submissionType = None
     self.reports = []
     self.renderedFiles = set()  # filing-level rendered files
     self.reportZip = None
     if responseZipStream:
         self.setReportZipStreamMode('w')
     else:
         try:  #zipOutputFile only present with EdgarRenderer plugin options
             if options and options.zipOutputFile:
                 if not os.path.isabs(options.zipOutputFile):
                     zipOutDir = os.path.dirname(filesource.basefile)
                     zipOutFile = os.path.join(zipOutDir,
                                               options.zipOutputFile)
                 else:
                     zipOutFile = options.zipOutputFile
                 self.reportZip = zipfile.ZipFile(zipOutFile, 'w',
                                                  zipfile.ZIP_DEFLATED,
                                                  True)
         except AttributeError:
             self.reportZip = None
     self.errorCaptureLevel = errorCaptureLevel or logging._checkLevel(
         "INCONSISTENCY")
     self.errors = []
     self.arelleUnitTests = {}  # copied from each instance loaded
     for pluginXbrlMethod in pluginClassMethods("Security.Crypt.Init"):
         pluginXbrlMethod(self, options, filesource, entrypointfiles,
                          sourceZipStream)
Exemple #36
0
 def start(self, tag, attrib, nsmap=None):
     modelXbrl.streamingParentModelObject = self.currentMdlObj # pass parent to makeelement for ModelObjectFactory
     mdlObj = _parser.makeelement(tag, attrib=attrib, nsmap=nsmap)
     mdlObj.sourceline = 1
     if self.newTree:
         self.newTree = False
         self.currentMdlObj = mdlObj
         modelDocument = ModelDocument(modelXbrl, Type.INSTANCE, mappedUri, filepath, mdlObj.getroottree())
         modelXbrl.modelDocument = modelDocument # needed for incremental validation
         mdlObj.init(modelDocument)
         modelDocument.parser = _parser # needed for XmlUtil addChild's makeelement 
         modelDocument.parserLookupName = _parserLookupName
         modelDocument.parserLookupClass = _parserLookupClass
         modelDocument.xmlRootElement = mdlObj
         modelDocument.schemaLocationElements.add(mdlObj)
         modelDocument.documentEncoding = _encoding
         modelDocument._creationSoftwareComment = creationSoftwareComment
         modelXbrl.info("streamingExtensions:streaming",
                        _("Stream processing this instance."),
                        modelObject = modelDocument)
     else:
         self.currentMdlObj.append(mdlObj)
         self.currentMdlObj = mdlObj
         mdlObj._init()
         ns = mdlObj.namespaceURI
         ln = mdlObj.localName
         if (self.beforeInstanceStream and (
             (ns == XbrlConst.link and ln not in ("schemaRef", "linkbaseRef")) or
             (ns == XbrlConst.xbrli and ln in ("context", "unit")) or
             (ns not in (XbrlConst.link, XbrlConst.xbrli)))):
             self.beforeInstanceStream = False
             if _streamingExtensionsValidate:
                 instValidator.validate(modelXbrl, modelXbrl.modelManager.formulaOptions.typedParameters())
             else: # need default dimensions
                 ValidateXbrlDimensions.loadDimensionDefaults(modelXbrl)
         elif not self.beforeInstanceStream and self.beforeStartStreamingPlugin:
             for pluginMethod in pluginClassMethods("Streaming.Start"):
                 pluginMethod(modelXbrl)
             self.beforeStartStreamingPlugin = False
     return mdlObj
 def expected(self):
     for pluginXbrlMethod in pluginClassMethods(u"ModelTestcaseVariation.ExpectedResult"):
         expected = pluginXbrlMethod(self)
         if expected:
             return expected
     # default behavior without plugins
     if self.localName == u"testcase":
         return self.document.basename[:4]   #starts with PASS or FAIL
     elif self.localName == u"testGroup":  #w3c testcase
         instanceTestElement = XmlUtil.descendant(self, None, u"instanceTest")
         if instanceTestElement is not None: # take instance first
             return XmlUtil.descendantAttr(instanceTestElement, None, u"expected", u"validity")
         else:
             schemaTestElement = XmlUtil.descendant(self, None, u"schemaTest")
             if schemaTestElement is not None:
                 return XmlUtil.descendantAttr(schemaTestElement, None, u"expected", u"validity")
     errorElement = XmlUtil.descendant(self, None, u"error")
     if errorElement is not None:
         return ModelValue.qname(errorElement, XmlUtil.text(errorElement))
     resultElement = XmlUtil.descendant(self, None, u"result")
     if resultElement is not None:
         expected = resultElement.get(u"expected")
         if expected:
             return expected
         for assertElement in XmlUtil.children(resultElement, None, u"assert"):
             num = assertElement.get(u"num")
             if len(num) == 5:
                 return u"EFM.{0}.{1}.{2}".format(num[0],num[1:3],num[3:6])
         asserTests = {}
         for atElt in XmlUtil.children(resultElement, None, u"assertionTests"):
             try:
                 asserTests[atElt.get(u"assertionID")] = (_INT(atElt.get(u"countSatisfied")),_INT(atElt.get(u"countNotSatisfied")))
             except ValueError:
                 pass
         if asserTests:
             return asserTests
     elif self.get(u"result"):
         return self.get(u"result")
             
     return None
Exemple #38
0
 def resetProxies(self, httpProxyTuple):
     # for ntlm user and password are required
     self.hasNTLM = False
     self._httpProxyTuple = httpProxyTuple # save for resetting in noCertificateCheck setter
     if isinstance(httpProxyTuple,(tuple,list)) and len(httpProxyTuple) == 5:
         useOsProxy, _urlAddr, _urlPort, user, password = httpProxyTuple
         _proxyDirFmt = proxyDirFmt(httpProxyTuple)
         # only try ntlm if user and password are provided because passman is needed
         if user and not useOsProxy:
             for pluginXbrlMethod in pluginClassMethods("Proxy.HTTPNtlmAuthHandler"):
                 HTTPNtlmAuthHandler = pluginXbrlMethod()
                 if HTTPNtlmAuthHandler is not None:
                     self.hasNTLM = True
             if not self.hasNTLM: # try for python site-packages ntlm
                 try:
                     from ntlm import HTTPNtlmAuthHandler
                     self.hasNTLM = True
                 except ImportError:
                     pass
         if self.hasNTLM:    
             pwrdmgr = proxyhandlers.HTTPPasswordMgrWithDefaultRealm()
             pwrdmgr.add_password(None, _proxyDirFmt["http"], user, password)
             self.proxy_handler = proxyhandlers.ProxyHandler({})
             self.proxy_auth_handler = proxyhandlers.ProxyBasicAuthHandler(pwrdmgr)
             self.http_auth_handler = proxyhandlers.HTTPBasicAuthHandler(pwrdmgr)
             self.ntlm_auth_handler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(pwrdmgr)
             proxyHandlers = [self.proxy_handler, self.ntlm_auth_handler, self.proxy_auth_handler, self.http_auth_handler]          
     if not self.hasNTLM:
         self.proxy_handler = proxyhandlers.ProxyHandler(proxyDirFmt(httpProxyTuple))
         self.proxy_auth_handler = proxyhandlers.ProxyBasicAuthHandler()
         self.http_auth_handler = proxyhandlers.HTTPBasicAuthHandler()
         proxyHandlers = [self.proxy_handler, self.proxy_auth_handler, self.http_auth_handler]
     if ssl and self.noCertificateCheck:
         context = ssl.create_default_context()
         context.check_hostname = False
         context.verify_mode = ssl.CERT_NONE
         proxyHandlers.append(proxyhandlers.HTTPSHandler(context=context))
     self.opener = proxyhandlers.build_opener(*proxyHandlers)
Exemple #39
0
def testcaseVariationXbrlLoaded(testcaseModelXbrl, instanceModelXbrl):
    # Validate of RSS feed item or testcase variation (simulates filing & cmd line load events
    modelManager = instanceModelXbrl.modelManager
    if (hasattr(testcaseModelXbrl, "efmOptions")
            and modelManager.validateDisclosureSystem
            and getattr(modelManager.disclosureSystem, "EFMplugin", False) and
        (instanceModelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE
         or instanceModelXbrl.modelDocument.type
         == ModelDocument.Type.INLINEXBRL)):
        cntlr = modelManager.cntlr
        options = testcaseModelXbrl.efmOptions
        entrypointFiles = [{"file": instanceModelXbrl.modelDocument.uri}]
        modelManager.efmFiling = Filing(cntlr, options,
                                        instanceModelXbrl.fileSource,
                                        entrypointFiles, None, None)
        # this event is called for filings (of instances) as well as test cases, for test case it just keeps options accessible
        for pluginXbrlMethod in pluginClassMethods(
                "EdgarRenderer.Filing.Start"):
            pluginXbrlMethod(cntlr, options, entrypointFiles,
                             modelManager.efmFiling)
        modelManager.efmFiling.addReport(instanceModelXbrl)
        _report = modelManager.efmFiling.reports[-1]
        _report.entryPoint = entrypointFiles[0]
Exemple #40
0
def testcaseVariationXbrlLoaded(testcaseModelXbrl, instanceModelXbrl,
                                modelTestcaseVariation, *args, **kwargs):
    # Validate of RSS feed item or testcase variation (simulates filing & cmd line load events
    modelManager = instanceModelXbrl.modelManager
    if (hasattr(testcaseModelXbrl, "efmOptions")
            and modelManager.validateDisclosureSystem
            and getattr(modelManager.disclosureSystem, "EFMplugin", False) and
        (instanceModelXbrl.modelDocument.type == ModelDocument.Type.INSTANCE
         or instanceModelXbrl.modelDocument.type
         == ModelDocument.Type.INLINEXBRL)):
        cntlr = modelManager.cntlr
        options = testcaseModelXbrl.efmOptions
        entrypointFiles = [{"file": instanceModelXbrl.modelDocument.uri}]
        if not hasattr(modelManager, "efmFiling"):  # first instance of filing
            modelManager.efmFiling = Filing(
                cntlr, options, instanceModelXbrl.fileSource, entrypointFiles,
                None, None, instanceModelXbrl.errorCaptureLevel)
            # this event is called for filings (of instances) as well as test cases, for test case it just keeps options accessible
            for pluginXbrlMethod in pluginClassMethods(
                    "EdgarRenderer.Filing.Start"):
                pluginXbrlMethod(cntlr, options, entrypointFiles,
                                 modelManager.efmFiling)
        modelManager.efmFiling.addReport(instanceModelXbrl)
        _report = modelManager.efmFiling.reports[-1]
        _report.entryPoint = entrypointFiles[0]
        modelManager.efmFiling.arelleUnitTests = instanceModelXbrl.arelleUnitTests.copy(
        )  # allow unit tests to be used after instance processing finished
        # check for parameters on instance
        for _instanceElt in XmlUtil.descendants(modelTestcaseVariation, "*",
                                                "instance", "readMeFirst",
                                                "true", False):
            if instanceModelXbrl.modelDocument.uri.endswith(_instanceElt.text):
                if _instanceElt.get("exhibitType"):
                    _report.entryPoint[
                        "exhibitType"] = _report.exhibitType = _instanceElt.get(
                            "exhibitType")
                break
Exemple #41
0
 def test(self):
     process = psutil.Process(os.getpid())
     largeEntryPoint = "http://www.eba.europa.eu/eu/fr/xbrl/crr/fws/corep/its-2014-05/2015-02-16/mod/corep_ind.xsd"
     smallEntryPoint = "http://eiopa.europa.eu/eu/xbrl/s2md/fws/solvency/solvency2/2015-05-31/mod/d1s.xsd"
     application = Tk()
     cntlrWinMain = CntlrWinMain(application)
     application.protocol("WM_DELETE_WINDOW", cntlrWinMain.quit)
     
     cntlrWinMain.setTestMode(True)
     for pluginMethod in pluginClassMethods("DevTesting.GetTestContext"):
         testContext = pluginMethod()
         break
     testContext.checkMemoryOnClose = True
     testDir = os.path.dirname(os.path.abspath(sys.modules[__name__].__file__))
     testContext.saveFilePath = testDir + "/tmp/a1.xbrl"
     testContext.dumpFilePrefix = testDir + "/tmp/dump_"
     
     tr = tracker.SummaryTracker()
     
     prevMemoryConsumed = 0
     
     for idx in range(4):
         print("\nIteration " + str(idx))
         cntlrWinMain.fileOpenFile(largeEntryPoint)
         maxSize = DevTesting.humanizeSize(process.memory_info()[0])
         cntlrWinMain.logClear()
         cntlrWinMain.fileClose()
     
         tr.print_diff()
         memoryConsumed = process.memory_info()[0]
         print("Memory consumed: " + DevTesting.humanizeSize(memoryConsumed) + " max= " + maxSize)
         diffMemeory = memoryConsumed - prevMemoryConsumed
         print(str(diffMemeory))
         if idx > 1:
             assert diffMemeory < 60000000, "Check memory leaks regression"
         prevMemoryConsumed = memoryConsumed
Exemple #42
0
def parse(modelObject, xpathExpression, element, name, traceType):
    from arelle.ModelFormulaObject import Trace
    global modelXbrl, pluginCustomFunctions
    modelXbrl = modelObject.modelXbrl
    global exprStack
    exprStack = []
    global xmlElement
    xmlElement = element
    returnProg = None
    pluginCustomFunctions = {}
    
    for pluginXbrlMethod in pluginClassMethods("Formula.CustomFunctions"):
        pluginCustomFunctions.update(pluginXbrlMethod())


    # throws ParseException
    if xpathExpression and len(xpathExpression) > 0:
        # normalize End of Line
        try:
            formulaOptions = modelXbrl.modelManager.formulaOptions

            normalizedExpr = normalizeExpr( xpathExpression )

            # for debugging parser looping or stack recursion, uncomment this:
            # modelObject.modelXbrl.modelManager.showStatus(_("Parsing file {0} line {1} expr {2}").format(element.modelDocument.basename,element.sourceline,normalizedExpr))

            # should be option "compiled code"
            
            if ((formulaOptions.traceVariableSetExpressionSource and traceType == Trace.VARIABLE_SET) or
                (formulaOptions.traceVariableExpressionSource and traceType == Trace.VARIABLE) or
                (formulaOptions.traceCallExpressionSource and traceType == Trace.CALL)):
                modelXbrl.info("formula:trace", "Source %(name)s %(source)s",
                modelObject=element,
                name=name,
                source=normalizedExpr)
            exprStack.append( ProgHeader(modelObject,name,element,normalizedExpr,traceType) )

            L = xpathExpr.parseString( normalizedExpr, parseAll=True )
            
            #modelXbrl.error( _("AST {0} {1}").format(name, L),
            #    "info", "formula:trace")

            # should be option "compiled code"
            if ((formulaOptions.traceVariableSetExpressionCode and traceType == Trace.VARIABLE_SET) or
                (formulaOptions.traceVariableExpressionCode and traceType == Trace.VARIABLE) or
                (formulaOptions.traceCallExpressionCode and traceType == Trace.CALL)):
                modelXbrl.info("formula:trace", _("Code %(name)s %(source)s"),
                modelObject=element,
                name=name,
                source=exprStack)
                
        except (ParseException, ParseSyntaxException) as err:
            modelXbrl.error("err:XPST0003",
                _("Parse error in %(name)s error: %(error)s \n%(source)s"),
                modelObject=element,
                name=name,
                error=err, 
                source=exceptionErrorIndication(err))
            # insert after ProgHeader before ordinary executable expression that may have successfully compiled
            exprStack.insert(1, OperationDef(normalizedExpr, 0, 
                                             QNameDef(0, "fn", XbrlConst.fn, "error"), 
                                             (OperationDef(normalizedExpr, 0, 
                                                           QNameDef(0, "fn", XbrlConst.fn, "QName"),
                                                           (XbrlConst.xpath2err, "err:XPST0003"),False),
                                              str(err)), False))
        except (ValueError) as err:
            modelXbrl.error("parser:unableToParse",
                _("Parsing terminated in %(name)s due to error: %(error)s \n%(source)s"),
                modelObject=element,
                name=name,
                error=err, 
                source=normalizedExpr)
            modelXbrl.debug("debug", str(traceback.format_exception(*sys.exc_info())))
        
        '''
        code = []
        compile(exprStack, code)
        pyCode = ''.join(code)
        val.modelXbrl.error(
            _("PyCode {0} {1}").format(
                 name,
                 pyCode),
            "info", "formula:trace")
        return pyCode
        '''
        returnProg = exprStack
    exprStack = [] # dereference
    xmlElement = None
    modelXbrl = None
    return returnProg
Exemple #43
0
    def select(self, name):
        self.clear()
        if not name:
            return True  # nothing to load
        result = False
        status = _("loading disclosure system and mappings")
        try:
            if name:
                isSelected = False
                for url in self.urls:  # urls in revese order, last plugin first
                    xmldoc = etree.parse(url)
                    for dsElt in xmldoc.iter(tag="DisclosureSystem"):
                        namesStr = dsElt.get("names")
                        if namesStr:
                            names = namesStr.split("|")
                            if name in names:
                                self.names = names
                                self.name = self.names[0]
                                self.validationType = dsElt.get(
                                    "validationType")
                                self.exclusiveTypesPattern = compileAttrPattern(
                                    dsElt,
                                    "exclusiveTypesPattern",
                                    patternIfNoAttr=None)
                                if self.validationType not in self.pluginTypes:
                                    self.EFM = self.validationType == "EFM"
                                    self.GFM = self.validationType == "GFM"
                                    self.EFMorGFM = self.EFM or self.GFM
                                    self.HMRC = self.validationType == "HMRC"
                                    self.SBRNL = self.validationType == "SBR.NL"
                                for pluginXbrlMethod in pluginClassMethods(
                                        "DisclosureSystem.Types"):
                                    for typeName, typeTestVariable in pluginXbrlMethod(
                                            self):
                                        setattr(
                                            self, typeTestVariable,
                                            self.validationType == typeName)
                                self.validateFileText = dsElt.get(
                                    "validateFileText") == "true"
                                if dsElt.get("allowedExternalHrefPattern"):
                                    self.allowedExternalHrefPattern = re.compile(
                                        dsElt.get(
                                            "allowedExternalHrefPattern"))
                                self.blockDisallowedReferences = dsElt.get(
                                    "blockDisallowedReferences") == "true"
                                try:
                                    self.maxSubmissionSubdirectoryEntryNesting = int(
                                        dsElt.get(
                                            "maxSubmissionSubdirectoryEntryNesting"
                                        ))
                                except (ValueError, TypeError):
                                    self.maxSubmissionSubdirectoryEntryNesting = 0
                                self.defaultXmlLang = dsElt.get(
                                    "defaultXmlLang")
                                if dsElt.get(
                                        "defaultXmlEncoding", default=None
                                ) is not None:  # don't reset from utf-8 unless supplied with a value
                                    self.defaultXmlEncoding = dsElt.get(
                                        "defaultXmlEncoding"
                                    )  # may be an empty string
                                self.xmlLangPattern = compileAttrPattern(
                                    dsElt, "xmlLangPattern")
                                self.xmlLangIsInheritable = dsElt.get(
                                    "xmlLangIsInheritable", "true") == "true"
                                self.defaultLanguage = dsElt.get(
                                    "defaultLanguage")
                                if dsElt.get("standardTaxonomiesUrl"):
                                    self.standardTaxonomiesUrl = self.modelManager.cntlr.webCache.normalizeUrl(
                                        dsElt.get("standardTaxonomiesUrl"),
                                        url)
                                if dsElt.get("mappingsUrl"):
                                    self.mappingsUrl = self.modelManager.cntlr.webCache.normalizeUrl(
                                        dsElt.get("mappingsUrl"), url)
                                if dsElt.get(
                                        "utrUrl"
                                ):  # may be mapped by mappingsUrl entries, see below
                                    self.utrUrl = self.modelManager.cntlr.webCache.normalizeUrl(
                                        dsElt.get("utrUrl"), url)
                                self.identifierSchemePattern = compileAttrPattern(
                                    dsElt, "identifierSchemePattern")
                                self.identifierValuePattern = compileAttrPattern(
                                    dsElt, "identifierValuePattern")
                                self.identifierValueName = dsElt.get(
                                    "identifierValueName")
                                self.contextElement = dsElt.get(
                                    "contextElement")
                                self.roleDefinitionPattern = compileAttrPattern(
                                    dsElt, "roleDefinitionPattern")
                                self.labelCheckPattern = compileAttrPattern(
                                    dsElt, "labelCheckPattern", re.DOTALL)
                                self.labelTrimPattern = compileAttrPattern(
                                    dsElt, "labelTrimPattern", re.DOTALL)
                                self.deiNamespacePattern = compileAttrPattern(
                                    dsElt, "deiNamespacePattern")
                                self.deiAmendmentFlagElement = dsElt.get(
                                    "deiAmendmentFlagElement")
                                self.deiCurrentFiscalYearEndDateElement = dsElt.get(
                                    "deiCurrentFiscalYearEndDateElement")
                                self.deiDocumentFiscalYearFocusElement = dsElt.get(
                                    "deiDocumentFiscalYearFocusElement")
                                self.deiDocumentPeriodEndDateElement = dsElt.get(
                                    "deiDocumentPeriodEndDateElement")
                                self.deiFilerIdentifierElement = dsElt.get(
                                    "deiFilerIdentifierElement")
                                self.deiFilerNameElement = dsElt.get(
                                    "deiFilerNameElement")
                                self.logLevelFilter = dsElt.get(
                                    "logLevelFilter")
                                self.logCodeFilter = dsElt.get("logCodeFilter")
                                self.standardTaxonomyDatabase = dsElt.get(
                                    "standardTaxonomyDatabase")
                                self.standardTaxonomyUrlPattern = compileAttrPattern(
                                    dsElt, "standardTaxonomyUrlPattern")

                                self.selection = self.name
                                isSelected = True
                                result = True
                                break
                    if isSelected:
                        break
            self.loadMappings()
            self.utrUrl = self.mappedUrl(
                self.utrUrl)  # utr may be mapped, change to its mapped entry
            self.loadStandardTaxonomiesDict()
            self.utrTypeEntries = None  # clear any prior loaded entries
            # set log level filters (including resetting prior disclosure systems values if no such filter)
            self.modelManager.cntlr.setLogLevelFilter(
                self.logLevelFilter
            )  # None or "" clears out prior filter if any
            self.modelManager.cntlr.setLogCodeFilter(self.logCodeFilter)
            if result:
                status = _("loaded")
            else:
                status = _("unable to load disclosure system {}").format(name)
                self.modelManager.cntlr.addToLog(
                    _("Disclosure System \"%(name)s\" not recognized (a plug-in may be needed)."
                      ),
                    messageCode="arelle:disclosureSystemName",
                    messageArgs={"name": name},
                    level=logging.ERROR)

        except (EnvironmentError, etree.LxmlError) as err:
            status = _("exception during loading")
            result = False
            self.modelManager.cntlr.addToLog(
                _("Disclosure System \"%(name)s\" loading error: %(error)s"),
                messageCode="arelle:disclosureSystemLoadingError",
                messageArgs={
                    "error": str(err),
                    "name": name
                },
                level=logging.ERROR)
            etree.clear_error_log()
        self.modelManager.cntlr.showStatus(
            _("Disclosure system and mappings {0}: {1}").format(status, name),
            3500)
        return result
Exemple #44
0
 def validateTestcase(self, testcase):
     self.modelXbrl.info("info", "Testcase", modelDocument=testcase)
     self.modelXbrl.viewModelObject(testcase.objectId())
     if hasattr(testcase, "testcaseVariations"):
         for modelTestcaseVariation in testcase.testcaseVariations:
             # update ui thread via modelManager (running in background here)
             self.modelXbrl.modelManager.viewModelObject(self.modelXbrl, modelTestcaseVariation.objectId())
             # is this a versioning report?
             resultIsVersioningReport = modelTestcaseVariation.resultIsVersioningReport
             resultIsXbrlInstance = modelTestcaseVariation.resultIsXbrlInstance
             formulaOutputInstance = None
             inputDTSes = defaultdict(list)
             baseForElement = testcase.baseForElement(modelTestcaseVariation)
             # try to load instance document
             self.modelXbrl.info("info", _("Variation %(id)s %(name)s: %(expected)s - %(description)s"),
                                 modelObject=modelTestcaseVariation, 
                                 id=modelTestcaseVariation.id, 
                                 name=modelTestcaseVariation.name, 
                                 expected=modelTestcaseVariation.expected, 
                                 description=modelTestcaseVariation.description)
             errorCaptureLevel = modelTestcaseVariation.severityLevel # default is INCONSISTENCY
             parameters = modelTestcaseVariation.parameters.copy()
             for readMeFirstUri in modelTestcaseVariation.readMeFirstUris:
                 if isinstance(readMeFirstUri,tuple):
                     # dtsName is for formula instances, but is from/to dts if versioning
                     dtsName, readMeFirstUri = readMeFirstUri
                 elif resultIsVersioningReport:
                     if inputDTSes: dtsName = "to"
                     else: dtsName = "from"
                 else:
                     dtsName = None
                 if resultIsVersioningReport and dtsName: # build multi-schemaRef containing document
                     if dtsName in inputDTSes:
                         dtsName = inputDTSes[dtsName]
                     else:
                         modelXbrl = ModelXbrl.create(self.modelXbrl.modelManager, 
                                      Type.DTSENTRIES,
                                      self.modelXbrl.modelManager.cntlr.webCache.normalizeUrl(readMeFirstUri[:-4] + ".dts", baseForElement),
                                      isEntry=True,
                                      errorCaptureLevel=errorCaptureLevel)
                     DTSdoc = modelXbrl.modelDocument
                     DTSdoc.inDTS = True
                     doc = modelDocumentLoad(modelXbrl, readMeFirstUri, base=baseForElement)
                     if doc is not None:
                         DTSdoc.referencesDocument[doc] = ModelDocumentReference("import", DTSdoc.xmlRootElement)  #fake import
                         doc.inDTS = True
                 else: # not a multi-schemaRef versioning report
                     if self.useFileSource.isArchive:
                         modelXbrl = ModelXbrl.load(self.modelXbrl.modelManager, 
                                                    readMeFirstUri,
                                                    _("validating"), 
                                                    base=baseForElement,
                                                    useFileSource=self.useFileSource,
                                                    errorCaptureLevel=errorCaptureLevel)
                     else: # need own file source, may need instance discovery
                         filesource = FileSource.FileSource(readMeFirstUri, self.modelXbrl.modelManager.cntlr)
                         if filesource and not filesource.selection and filesource.isArchive:
                             for _archiveFile in filesource.dir: # find instance document in archive
                                 filesource.select(_archiveFile)
                                 if ModelDocument.Type.identify(filesource, filesource.url) in (ModelDocument.Type.INSTANCE, ModelDocument.Type.INLINEXBRL):
                                     break # use this selection
                         modelXbrl = ModelXbrl.load(self.modelXbrl.modelManager, 
                                                    filesource,
                                                    _("validating"), 
                                                    base=baseForElement,
                                                    errorCaptureLevel=errorCaptureLevel)
                 if modelXbrl.modelDocument is None:
                     self.modelXbrl.error("arelle:notLoaded",
                          _("Testcase %(id)s %(name)s document not loaded: %(file)s"),
                          modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, file=os.path.basename(readMeFirstUri))
                     modelXbrl.close()
                     self.determineNotLoadedTestStatus(modelTestcaseVariation)
                 elif resultIsVersioningReport:
                     inputDTSes[dtsName] = modelXbrl
                 elif modelXbrl.modelDocument.type == Type.VERSIONINGREPORT:
                     ValidateVersReport.ValidateVersReport(self.modelXbrl).validate(modelXbrl)
                     self.determineTestStatus(modelTestcaseVariation, modelXbrl.errors)
                     modelXbrl.close()
                 elif testcase.type == Type.REGISTRYTESTCASE:
                     self.instValidator.validate(modelXbrl)  # required to set up dimensions, etc
                     self.instValidator.executeCallTest(modelXbrl, modelTestcaseVariation.id, 
                                modelTestcaseVariation.cfcnCall, modelTestcaseVariation.cfcnTest)
                     self.determineTestStatus(modelTestcaseVariation, modelXbrl.errors)
                     self.instValidator.close()
                     modelXbrl.close()
                 else:
                     inputDTSes[dtsName].append(modelXbrl)
                     # validate except for formulas
                     _hasFormulae = modelXbrl.hasFormulae
                     modelXbrl.hasFormulae = False
                     try:
                         for pluginXbrlMethod in pluginClassMethods("TestcaseVariation.Xbrl.Loaded"):
                             pluginXbrlMethod(self.modelXbrl, modelXbrl, modelTestcaseVariation)
                         self.instValidator.validate(modelXbrl, parameters)
                         for pluginXbrlMethod in pluginClassMethods("TestcaseVariation.Xbrl.Validated"):
                             pluginXbrlMethod(self.modelXbrl, modelXbrl)
                     except Exception as err:
                         self.modelXbrl.error("exception",
                             _("Testcase variation validation exception: %(error)s, instance: %(instance)s"),
                             modelXbrl=modelXbrl, instance=modelXbrl.modelDocument.basename, error=err, exc_info=True)
                     modelXbrl.hasFormulae = _hasFormulae
             if resultIsVersioningReport and modelXbrl.modelDocument:
                 versReportFile = modelXbrl.modelManager.cntlr.webCache.normalizeUrl(
                     modelTestcaseVariation.versioningReportUri, baseForElement)
                 if os.path.exists(versReportFile): #validate existing
                     modelVersReport = ModelXbrl.load(self.modelXbrl.modelManager, versReportFile, _("validating existing version report"))
                     if modelVersReport and modelVersReport.modelDocument and modelVersReport.modelDocument.type == Type.VERSIONINGREPORT:
                         ValidateVersReport.ValidateVersReport(self.modelXbrl).validate(modelVersReport)
                         self.determineTestStatus(modelTestcaseVariation, modelVersReport.errors)
                         modelVersReport.close()
                 elif len(inputDTSes) == 2:
                     ModelVersReport.ModelVersReport(self.modelXbrl).diffDTSes(
                           versReportFile, inputDTSes["from"], inputDTSes["to"])
                     modelTestcaseVariation.status = "generated"
                 else:
                     self.modelXbrl.error("arelle:notLoaded",
                          _("Testcase %(id)s %(name)s DTSes not loaded, unable to generate versioning report: %(file)s"),
                          modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, file=os.path.basename(readMeFirstUri))
                     modelTestcaseVariation.status = "failed"
                 for inputDTS in inputDTSes.values():
                     inputDTS.close()
                 del inputDTSes # dereference
             elif inputDTSes:
                 # validate schema, linkbase, or instance
                 modelXbrl = inputDTSes[None][0]
                 for dtsName, inputDTS in inputDTSes.items():  # input instances are also parameters
                     if dtsName: # named instance
                         parameters[dtsName] = (None, inputDTS) #inputDTS is a list of modelXbrl's (instance DTSes)
                     elif len(inputDTS) > 1: # standard-input-instance with multiple instance documents
                         parameters[XbrlConst.qnStandardInputInstance] = (None, inputDTS) # allow error detection in validateFormula
                 if modelXbrl.hasTableRendering or modelTestcaseVariation.resultIsTable:
                     RenderingEvaluator.init(modelXbrl)
                 if modelXbrl.hasFormulae:
                     try:
                         # validate only formulae
                         self.instValidator.parameters = parameters
                         ValidateFormula.validate(self.instValidator)
                     except Exception as err:
                         self.modelXbrl.error("exception",
                             _("Testcase formula variation validation exception: %(error)s, instance: %(instance)s"),
                             modelXbrl=modelXbrl, instance=modelXbrl.modelDocument.basename, error=err, exc_info=True)
                 if modelTestcaseVariation.resultIsInfoset and self.modelXbrl.modelManager.validateInfoset:
                     for pluginXbrlMethod in pluginClassMethods("Validate.Infoset"):
                         pluginXbrlMethod(modelXbrl, modelTestcaseVariation.resultInfosetUri)
                     infoset = ModelXbrl.load(self.modelXbrl.modelManager, 
                                              modelTestcaseVariation.resultInfosetUri,
                                                _("loading result infoset"), 
                                                base=baseForElement,
                                                useFileSource=self.useFileSource,
                                                errorCaptureLevel=errorCaptureLevel)
                     if infoset.modelDocument is None:
                         self.modelXbrl.error("arelle:notLoaded",
                             _("Testcase %(id)s %(name)s result infoset not loaded: %(file)s"),
                             modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, 
                             file=os.path.basename(modelTestcaseVariation.resultXbrlInstance))
                         modelTestcaseVariation.status = "result infoset not loadable"
                     else:   # check infoset
                         ValidateInfoset.validate(self.instValidator, modelXbrl, infoset)
                     infoset.close()
                 if modelTestcaseVariation.resultIsTable: # and self.modelXbrl.modelManager.validateInfoset:
                     # diff (or generate) table infoset
                     resultTableUri = modelXbrl.modelManager.cntlr.webCache.normalizeUrl(modelTestcaseVariation.resultTableUri, baseForElement)
                     if not any(alternativeValidation(modelXbrl, resultTableUri)
                                for alternativeValidation in pluginClassMethods("Validate.TableInfoset")):
                         ViewFileRenderedGrid.viewRenderedGrid(modelXbrl, resultTableUri, diffToFile=True)  # false to save infoset files
                 self.instValidator.close()
                 extraErrors = []
                 for pluginXbrlMethod in pluginClassMethods("TestcaseVariation.Validated"):
                     pluginXbrlMethod(self.modelXbrl, modelXbrl, extraErrors)
                 self.determineTestStatus(modelTestcaseVariation, [e for inputDTSlist in inputDTSes.values() for inputDTS in inputDTSlist for e in inputDTS.errors] + extraErrors) # include infoset errors in status
                 if modelXbrl.formulaOutputInstance and self.noErrorCodes(modelTestcaseVariation.actual): 
                     # if an output instance is created, and no string error codes, ignoring dict of assertion results, validate it
                     modelXbrl.formulaOutputInstance.hasFormulae = False #  block formulae on output instance (so assertion of input is not lost)
                     self.instValidator.validate(modelXbrl.formulaOutputInstance, modelTestcaseVariation.parameters)
                     self.determineTestStatus(modelTestcaseVariation, modelXbrl.formulaOutputInstance.errors)
                     if self.noErrorCodes(modelTestcaseVariation.actual): # if still 'clean' pass it forward for comparison to expected result instance
                         formulaOutputInstance = modelXbrl.formulaOutputInstance
                         modelXbrl.formulaOutputInstance = None # prevent it from being closed now
                     self.instValidator.close()
                 for inputDTSlist in inputDTSes.values():
                     for inputDTS in inputDTSlist:
                         inputDTS.close()
                 del inputDTSes # dereference
                 if resultIsXbrlInstance and formulaOutputInstance and formulaOutputInstance.modelDocument:
                     expectedInstance = ModelXbrl.load(self.modelXbrl.modelManager, 
                                                modelTestcaseVariation.resultXbrlInstanceUri,
                                                _("loading expected result XBRL instance"), 
                                                base=baseForElement,
                                                useFileSource=self.useFileSource,
                                                errorCaptureLevel=errorCaptureLevel)
                     if expectedInstance.modelDocument is None:
                         self.modelXbrl.error("arelle:notLoaded",
                             _("Testcase %(id)s %(name)s expected result instance not loaded: %(file)s"),
                             modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, 
                             file=os.path.basename(modelTestcaseVariation.resultXbrlInstance))
                         modelTestcaseVariation.status = "result not loadable"
                     else:   # compare facts
                         if len(expectedInstance.facts) != len(formulaOutputInstance.facts):
                             formulaOutputInstance.error("formula:resultFactCounts",
                                 _("Formula output %(countFacts)s facts, expected %(expectedFacts)s facts"),
                                 modelXbrl=modelXbrl, countFacts=len(formulaOutputInstance.facts),
                                      expectedFacts=len(expectedInstance.facts))
                         else:
                             for fact in expectedInstance.facts:
                                 unmatchedFactsStack = []
                                 if formulaOutputInstance.matchFact(fact, unmatchedFactsStack, deemP0inf=True) is None:
                                     if unmatchedFactsStack: # get missing nested tuple fact, if possible
                                         missingFact = unmatchedFactsStack[-1]
                                     else:
                                         missingFact = fact
                                     formulaOutputInstance.error("formula:expectedFactMissing",
                                         _("Formula output missing expected fact %(fact)s"),
                                         modelXbrl=missingFact, fact=missingFact.qname)
                         # for debugging uncomment next line to save generated instance document
                         # formulaOutputInstance.saveInstance(r"c:\temp\test-out-inst.xml")
                     expectedInstance.close()
                     del expectedInstance # dereference
                     self.determineTestStatus(modelTestcaseVariation, formulaOutputInstance.errors)
                     formulaOutputInstance.close()
                     del formulaOutputInstance
             # update ui thread via modelManager (running in background here)
             self.modelXbrl.modelManager.viewModelObject(self.modelXbrl, modelTestcaseVariation.objectId())
                 
         self.modelXbrl.modelManager.showStatus(_("ready"), 2000)
Exemple #45
0
    def validateTestcase(self, testcase):
        self.modelXbrl.info("info", "Testcase", modelDocument=testcase)
        self.modelXbrl.viewModelObject(testcase.objectId())
        if hasattr(testcase, "testcaseVariations"):
            for modelTestcaseVariation in testcase.testcaseVariations:
                # update ui thread via modelManager (running in background here)
                self.modelXbrl.modelManager.viewModelObject(self.modelXbrl, modelTestcaseVariation.objectId())
                # is this a versioning report?
                resultIsVersioningReport = modelTestcaseVariation.resultIsVersioningReport
                resultIsXbrlInstance = modelTestcaseVariation.resultIsXbrlInstance
                resultIsTaxonomyPackage = modelTestcaseVariation.resultIsTaxonomyPackage
                formulaOutputInstance = None
                inputDTSes = defaultdict(list)
                baseForElement = testcase.baseForElement(modelTestcaseVariation)
                # try to load instance document
                self.modelXbrl.info("info", _("Variation %(id)s %(name)s: %(expected)s - %(description)s"),
                                    modelObject=modelTestcaseVariation, 
                                    id=modelTestcaseVariation.id, 
                                    name=modelTestcaseVariation.name, 
                                    expected=modelTestcaseVariation.expected, 
                                    description=modelTestcaseVariation.description)
                errorCaptureLevel = modelTestcaseVariation.severityLevel # default is INCONSISTENCY
                parameters = modelTestcaseVariation.parameters.copy()
                for readMeFirstUri in modelTestcaseVariation.readMeFirstUris:
                    if isinstance(readMeFirstUri,tuple):
                        # dtsName is for formula instances, but is from/to dts if versioning
                        dtsName, readMeFirstUri = readMeFirstUri
                    elif resultIsVersioningReport:
                        if inputDTSes: dtsName = "to"
                        else: dtsName = "from"
                    else:
                        dtsName = None
                    if resultIsVersioningReport and dtsName: # build multi-schemaRef containing document
                        if dtsName in inputDTSes:
                            dtsName = inputDTSes[dtsName]
                        else:
                            modelXbrl = ModelXbrl.create(self.modelXbrl.modelManager, 
                                         Type.DTSENTRIES,
                                         self.modelXbrl.modelManager.cntlr.webCache.normalizeUrl(readMeFirstUri[:-4] + ".dts", baseForElement),
                                         isEntry=True,
                                         errorCaptureLevel=errorCaptureLevel)
                        DTSdoc = modelXbrl.modelDocument
                        DTSdoc.inDTS = True
                        doc = modelDocumentLoad(modelXbrl, readMeFirstUri, base=baseForElement)
                        if doc is not None:
                            DTSdoc.referencesDocument[doc] = ModelDocumentReference("import", DTSdoc.xmlRootElement)  #fake import
                            doc.inDTS = True
                    elif resultIsTaxonomyPackage:
                        from arelle import PackageManager, PrototypeInstanceObject
                        dtsName = readMeFirstUri
                        modelXbrl = PrototypeInstanceObject.XbrlPrototype(self.modelXbrl.modelManager, readMeFirstUri)
                        PackageManager.packageInfo(self.modelXbrl.modelManager.cntlr, readMeFirstUri, reload=True, errors=modelXbrl.errors)
                    else: # not a multi-schemaRef versioning report
                        if self.useFileSource.isArchive:
                            modelXbrl = ModelXbrl.load(self.modelXbrl.modelManager, 
                                                       readMeFirstUri,
                                                       _("validating"), 
                                                       base=baseForElement,
                                                       useFileSource=self.useFileSource,
                                                       errorCaptureLevel=errorCaptureLevel)
                        else: # need own file source, may need instance discovery
                            filesource = FileSource.FileSource(readMeFirstUri, self.modelXbrl.modelManager.cntlr)
                            if filesource and not filesource.selection and filesource.isArchive:
                                for _archiveFile in filesource.dir: # find instance document in archive
                                    filesource.select(_archiveFile)
                                    if ModelDocument.Type.identify(filesource, filesource.url) in (ModelDocument.Type.INSTANCE, ModelDocument.Type.INLINEXBRL):
                                        break # use this selection
                            modelXbrl = ModelXbrl.load(self.modelXbrl.modelManager, 
                                                       filesource,
                                                       _("validating"), 
                                                       base=baseForElement,
                                                       errorCaptureLevel=errorCaptureLevel)
                        modelXbrl.isTestcaseVariation = True
                    if modelXbrl.modelDocument is None:
                        modelXbrl.error("arelle:notLoaded",
                             _("Testcase %(id)s %(name)s document not loaded: %(file)s"),
                             modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, file=os.path.basename(readMeFirstUri))
                        self.determineNotLoadedTestStatus(modelTestcaseVariation, modelXbrl.errors)
                        modelXbrl.close()
                    elif resultIsVersioningReport or resultIsTaxonomyPackage:
                        inputDTSes[dtsName] = modelXbrl
                    elif modelXbrl.modelDocument.type == Type.VERSIONINGREPORT:
                        ValidateVersReport.ValidateVersReport(self.modelXbrl).validate(modelXbrl)
                        self.determineTestStatus(modelTestcaseVariation, modelXbrl.errors)
                        modelXbrl.close()
                    elif testcase.type == Type.REGISTRYTESTCASE:
                        self.instValidator.validate(modelXbrl)  # required to set up dimensions, etc
                        self.instValidator.executeCallTest(modelXbrl, modelTestcaseVariation.id, 
                                   modelTestcaseVariation.cfcnCall, modelTestcaseVariation.cfcnTest)
                        self.determineTestStatus(modelTestcaseVariation, modelXbrl.errors)
                        self.instValidator.close()
                        modelXbrl.close()
                    else:
                        inputDTSes[dtsName].append(modelXbrl)
                        # validate except for formulas
                        _hasFormulae = modelXbrl.hasFormulae
                        modelXbrl.hasFormulae = False
                        try:
                            for pluginXbrlMethod in pluginClassMethods("TestcaseVariation.Xbrl.Loaded"):
                                pluginXbrlMethod(self.modelXbrl, modelXbrl, modelTestcaseVariation)
                            self.instValidator.validate(modelXbrl, parameters)
                            for pluginXbrlMethod in pluginClassMethods("TestcaseVariation.Xbrl.Validated"):
                                pluginXbrlMethod(self.modelXbrl, modelXbrl)
                        except Exception as err:
                            modelXbrl.error("exception:" + type(err).__name__,
                                _("Testcase variation validation exception: %(error)s, instance: %(instance)s"),
                                modelXbrl=modelXbrl, instance=modelXbrl.modelDocument.basename, error=err, exc_info=True)
                        modelXbrl.hasFormulae = _hasFormulae
                if resultIsVersioningReport and modelXbrl.modelDocument:
                    versReportFile = modelXbrl.modelManager.cntlr.webCache.normalizeUrl(
                        modelTestcaseVariation.versioningReportUri, baseForElement)
                    if os.path.exists(versReportFile): #validate existing
                        modelVersReport = ModelXbrl.load(self.modelXbrl.modelManager, versReportFile, _("validating existing version report"))
                        if modelVersReport and modelVersReport.modelDocument and modelVersReport.modelDocument.type == Type.VERSIONINGREPORT:
                            ValidateVersReport.ValidateVersReport(self.modelXbrl).validate(modelVersReport)
                            self.determineTestStatus(modelTestcaseVariation, modelVersReport.errors)
                            modelVersReport.close()
                    elif len(inputDTSes) == 2:
                        ModelVersReport.ModelVersReport(self.modelXbrl).diffDTSes(
                              versReportFile, inputDTSes["from"], inputDTSes["to"])
                        modelTestcaseVariation.status = "generated"
                    else:
                        modelXbrl.error("arelle:notLoaded",
                             _("Testcase %(id)s %(name)s DTSes not loaded, unable to generate versioning report: %(file)s"),
                             modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, file=os.path.basename(readMeFirstUri))
                        modelTestcaseVariation.status = "failed"
                    for inputDTS in inputDTSes.values():
                        inputDTS.close()
                    del inputDTSes # dereference
                elif resultIsTaxonomyPackage:
                    self.determineTestStatus(modelTestcaseVariation, modelXbrl.errors)
                    modelXbrl.close()
                elif inputDTSes:
                    # validate schema, linkbase, or instance
                    modelXbrl = inputDTSes[None][0]
                    for dtsName, inputDTS in inputDTSes.items():  # input instances are also parameters
                        if dtsName: # named instance
                            parameters[dtsName] = (None, inputDTS) #inputDTS is a list of modelXbrl's (instance DTSes)
                        elif len(inputDTS) > 1: # standard-input-instance with multiple instance documents
                            parameters[XbrlConst.qnStandardInputInstance] = (None, inputDTS) # allow error detection in validateFormula
                    if modelXbrl.hasTableRendering or modelTestcaseVariation.resultIsTable:
                        RenderingEvaluator.init(modelXbrl)
                    if modelXbrl.hasFormulae:
                        try:
                            # validate only formulae
                            self.instValidator.parameters = parameters
                            ValidateFormula.validate(self.instValidator)
                        except Exception as err:
                            modelXbrl.error("exception:" + type(err).__name__,
                                _("Testcase formula variation validation exception: %(error)s, instance: %(instance)s"),
                                modelXbrl=modelXbrl, instance=modelXbrl.modelDocument.basename, error=err, exc_info=True)
                    if modelTestcaseVariation.resultIsInfoset and self.modelXbrl.modelManager.validateInfoset:
                        for pluginXbrlMethod in pluginClassMethods("Validate.Infoset"):
                            pluginXbrlMethod(modelXbrl, modelTestcaseVariation.resultInfosetUri)
                        infoset = ModelXbrl.load(self.modelXbrl.modelManager, 
                                                 modelTestcaseVariation.resultInfosetUri,
                                                   _("loading result infoset"), 
                                                   base=baseForElement,
                                                   useFileSource=self.useFileSource,
                                                   errorCaptureLevel=errorCaptureLevel)
                        if infoset.modelDocument is None:
                            modelXbrl.error("arelle:notLoaded",
                                _("Testcase %(id)s %(name)s result infoset not loaded: %(file)s"),
                                modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, 
                                file=os.path.basename(modelTestcaseVariation.resultXbrlInstance))
                            modelTestcaseVariation.status = "result infoset not loadable"
                        else:   # check infoset
                            ValidateInfoset.validate(self.instValidator, modelXbrl, infoset)
                        infoset.close()
                    if modelTestcaseVariation.resultIsTable: # and self.modelXbrl.modelManager.validateInfoset:
                        # diff (or generate) table infoset
                        resultTableUri = modelXbrl.modelManager.cntlr.webCache.normalizeUrl(modelTestcaseVariation.resultTableUri, baseForElement)
                        if not any(alternativeValidation(modelXbrl, resultTableUri)
                                   for alternativeValidation in pluginClassMethods("Validate.TableInfoset")):
                            ViewFileRenderedGrid.viewRenderedGrid(modelXbrl, resultTableUri, diffToFile=True)  # false to save infoset files
                    self.instValidator.close()
                    extraErrors = []
                    for pluginXbrlMethod in pluginClassMethods("TestcaseVariation.Validated"):
                        pluginXbrlMethod(self.modelXbrl, modelXbrl, extraErrors)
                    self.determineTestStatus(modelTestcaseVariation, [e for inputDTSlist in inputDTSes.values() for inputDTS in inputDTSlist for e in inputDTS.errors] + extraErrors) # include infoset errors in status
                    if modelXbrl.formulaOutputInstance and self.noErrorCodes(modelTestcaseVariation.actual): 
                        # if an output instance is created, and no string error codes, ignoring dict of assertion results, validate it
                        modelXbrl.formulaOutputInstance.hasFormulae = False #  block formulae on output instance (so assertion of input is not lost)
                        self.instValidator.validate(modelXbrl.formulaOutputInstance, modelTestcaseVariation.parameters)
                        self.determineTestStatus(modelTestcaseVariation, modelXbrl.formulaOutputInstance.errors)
                        if self.noErrorCodes(modelTestcaseVariation.actual): # if still 'clean' pass it forward for comparison to expected result instance
                            formulaOutputInstance = modelXbrl.formulaOutputInstance
                            modelXbrl.formulaOutputInstance = None # prevent it from being closed now
                        self.instValidator.close()
                    compareIxResultInstance = getattr(modelXbrl, "extractedInlineInstance", False) and modelTestcaseVariation.resultXbrlInstanceUri
                    if compareIxResultInstance:
                        formulaOutputInstance = modelXbrl # compare modelXbrl to generated output instance
                        errMsgPrefix = "ix"
                    else: # delete input instances before formula output comparision
                        for inputDTSlist in inputDTSes.values():
                            for inputDTS in inputDTSlist:
                                inputDTS.close()
                        del inputDTSes # dereference
                        errMsgPrefix = "formula"
                    if resultIsXbrlInstance and formulaOutputInstance and formulaOutputInstance.modelDocument:
                        expectedInstance = ModelXbrl.load(self.modelXbrl.modelManager, 
                                                   modelTestcaseVariation.resultXbrlInstanceUri,
                                                   _("loading expected result XBRL instance"), 
                                                   base=baseForElement,
                                                   useFileSource=self.useFileSource,
                                                   errorCaptureLevel=errorCaptureLevel)
                        if expectedInstance.modelDocument is None:
                            self.modelXbrl.error("{}:expectedResultNotLoaded".format(errMsgPrefix),
                                _("Testcase %(id)s %(name)s expected result instance not loaded: %(file)s"),
                                modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, 
                                file=os.path.basename(modelTestcaseVariation.resultXbrlInstanceUri),
                                messageCodes=("formula:expectedResultNotLoaded","ix:expectedResultNotLoaded"))
                            modelTestcaseVariation.status = "result not loadable"
                        else:   # compare facts
                            if len(expectedInstance.facts) != len(formulaOutputInstance.facts):
                                formulaOutputInstance.error("{}:resultFactCounts".format(errMsgPrefix),
                                    _("Formula output %(countFacts)s facts, expected %(expectedFacts)s facts"),
                                    modelXbrl=modelXbrl, countFacts=len(formulaOutputInstance.facts),
                                    expectedFacts=len(expectedInstance.facts),
                                    messageCodes=("formula:resultFactCounts","ix:resultFactCounts"))
                            else:
                                formulaOutputFootnotesRelSet = ModelRelationshipSet(formulaOutputInstance, "XBRL-footnotes")
                                expectedFootnotesRelSet = ModelRelationshipSet(expectedInstance, "XBRL-footnotes")
                                def factFootnotes(fact, footnotesRelSet):
                                    footnotes = []
                                    footnoteRels = footnotesRelSet.fromModelObject(fact)
                                    if footnoteRels:
                                        # most process rels in same order between two instances, use labels to sort
                                        for i, footnoteRel in enumerate(sorted(footnoteRels,
                                                                               key=lambda r: (r.fromLabel,r.toLabel))):
                                            modelObject = footnoteRel.toModelObject
                                            if isinstance(modelObject, ModelResource):
                                                xml = modelObject.viewText().strip()
                                                footnotes.append("Footnote {}: {}".format(
                                                   i+1, # compare footnote with HTML serialized
                                                   xml,
                                                   #re.sub(r'\s+', ' ', collapseWhitespace(modelObject.stringValue))
                                                   ))
                                            elif isinstance(modelObject, ModelFact):
                                                footnotes.append("Footnoted fact {}: {} context: {} value: {}".format(
                                                    i+1,
                                                    modelObject.qname,
                                                    modelObject.contextID,
                                                    collapseWhitespace(modelObject.value)))
                                    return footnotes
                                for expectedInstanceFact in expectedInstance.facts:
                                    unmatchedFactsStack = []
                                    formulaOutputFact = formulaOutputInstance.matchFact(expectedInstanceFact, unmatchedFactsStack, deemP0inf=True)
                                    if formulaOutputFact is None:
                                        if unmatchedFactsStack: # get missing nested tuple fact, if possible
                                            missingFact = unmatchedFactsStack[-1]
                                        else:
                                            missingFact = expectedInstanceFact
                                        formulaOutputInstance.error("{}:expectedFactMissing".format(errMsgPrefix),
                                            _("Output missing expected fact %(fact)s"),
                                            modelXbrl=missingFact, fact=missingFact.qname,
                                            messageCodes=("formula:expectedFactMissing","ix:expectedFactMissing"))
                                    else: # compare footnotes
                                        expectedInstanceFactFootnotes = factFootnotes(expectedInstanceFact, expectedFootnotesRelSet)
                                        formulaOutputFactFootnotes = factFootnotes(formulaOutputFact, formulaOutputFootnotesRelSet)
                                        if expectedInstanceFactFootnotes != formulaOutputFactFootnotes:
                                            formulaOutputInstance.error("{}:expectedFactFootnoteDifference".format(errMsgPrefix),
                                                _("Output expected fact %(fact)s expected footnotes %(footnotes1)s produced footnotes %(footnotes2)s"),
                                                modelXbrl=(formulaOutputFact,expectedInstanceFact), fact=expectedInstanceFact.qname, footnotes1=expectedInstanceFactFootnotes, footnotes2=formulaOutputFactFootnotes,
                                                messageCodes=("formula:expectedFactFootnoteDifference","ix:expectedFactFootnoteDifference"))

                            # for debugging uncomment next line to save generated instance document
                            # formulaOutputInstance.saveInstance(r"c:\temp\test-out-inst.xml")
                        expectedInstance.close()
                        del expectedInstance # dereference
                        self.determineTestStatus(modelTestcaseVariation, formulaOutputInstance.errors)
                        formulaOutputInstance.close()
                        del formulaOutputInstance
                    if compareIxResultInstance:
                        for inputDTSlist in inputDTSes.values():
                            for inputDTS in inputDTSlist:
                                inputDTS.close()
                        del inputDTSes # dereference
                # update ui thread via modelManager (running in background here)
                self.modelXbrl.modelManager.viewModelObject(self.modelXbrl, modelTestcaseVariation.objectId())
                    
            self.modelXbrl.modelManager.showStatus(_("ready"), 2000)
Exemple #46
0
def runSaveTargetDocumentMenuCommand(cntlr,
                                     runInBackground=False,
                                     saveTargetFiling=False,
                                     encodeSavedXmlChars=False):
    # skip if another class handles saving (e.g., EdgarRenderer)
    for pluginXbrlMethod in pluginClassMethods(
            'InlineDocumentSet.SavesTargetInstance'):
        if pluginXbrlMethod():
            return  # saving of target instance is handled by another class
    # save DTS menu item has been invoked
    if (cntlr.modelManager is None or cntlr.modelManager.modelXbrl is None
            or cntlr.modelManager.modelXbrl.modelDocument.type
            not in (Type.INLINEXBRL, Type.INLINEXBRLDOCUMENTSET)):
        cntlr.addToLog("No inline XBRL document set loaded.")
        return
    modelDocument = cntlr.modelManager.modelXbrl.modelDocument
    if modelDocument.type == Type.INLINEXBRLDOCUMENTSET:
        targetFilename = modelDocument.targetDocumentPreferredFilename
        targetSchemaRefs = modelDocument.targetDocumentSchemaRefs
    else:
        filepath, fileext = os.path.splitext(modelDocument.filepath)
        if fileext not in (".xml", ".xbrl"):
            fileext = ".xbrl"
        targetFilename = filepath + fileext
        targetSchemaRefs = set(
            modelDocument.relativeUri(referencedDoc.uri)
            for referencedDoc in modelDocument.referencesDocument.keys()
            if referencedDoc.type == Type.SCHEMA)
    if runInBackground:
        import threading
        thread = threading.Thread(
            target=lambda _x=modelDocument.modelXbrl, _f=targetFilename, _s=
            targetSchemaRefs: saveTargetDocument(_x, _f, _s))
        thread.daemon = True
        thread.start()
    else:
        if saveTargetFiling:
            targetFilename = os.path.basename(targetFilename)
            filingZip = zipfile.ZipFile(saveTargetFiling, 'w',
                                        zipfile.ZIP_DEFLATED, True)
            filingFiles = set()

            # copy referencedDocs to two levels
            def addRefDocs(doc):
                for refDoc in doc.referencesDocument.keys():
                    if refDoc.uri not in filingFiles:
                        filingFiles.add(refDoc.uri)
                        addRefDocs(refDoc)

            addRefDocs(modelDocument)
        else:
            filingZip = None
            filingFiles = None
        saveTargetDocument(modelDocument.modelXbrl,
                           targetFilename,
                           targetSchemaRefs,
                           filingZip,
                           filingFiles,
                           encodeSavedXmlChars=encodeSavedXmlChars)
        if saveTargetFiling:
            instDir = os.path.dirname(
                modelDocument.uri.split(IXDS_DOC_SEPARATOR)[0])
            for refFile in filingFiles:
                if refFile.startswith(instDir):
                    filingZip.write(refFile,
                                    modelDocument.relativeUri(refFile))
def parentMenuCommand(cntl):
    for i in range(1, 100):
        for pluginMethod in pluginClassMethods(
                "Import.Unpackaged.Entry{}".format(i)):
            pluginMethod()
Exemple #48
0
def streamingExtensionsLoader(modelXbrl, mappedUri, filepath, *args, **kwargs):
    # check if big instance and has header with an initial incomplete tree walk (just 2 elements
    if not _streamingExtensionsCheck:
        return None

    # track whether modelXbrl has been validated by this streaming extension
    modelXbrl._streamingExtensionValidated = False

    def logSyntaxErrors(parsercontext):
        for error in parsercontext.error_log:
            modelXbrl.error(
                "xmlSchema:syntax",
                _("%(error)s, %(fileName)s, line %(line)s, column %(column)s, %(sourceAction)s source element"
                  ),
                modelObject=modelXbrl,
                fileName=os.path.basename(filepath),
                error=error.message,
                line=error.line,
                column=error.column,
                sourceAction="streaming")

    #### note: written for iterparse of lxml prior to version 3.3, otherwise rewrite to use XmlPullParser ###
    #### note: iterparse wants a binary file, but file is text mode
    _file, = modelXbrl.fileSource.file(filepath, binary=True)
    startedAt = time.time()
    modelXbrl.profileActivity()
    ''' this seems twice as slow as iterparse
    class instInfoTarget():
        def __init__(self, element_factory=None, parser=None):
            self.newTree = True
            self.streamingAspects = None
            self.foundInstance = False
            self.creationSoftwareComment = ''
            self.currentEltTag = "(before xbrli:xbrl)"
            self.numRootFacts = 0
        def start(self, tag, attrib, nsmap=None):
            if self.newTree:
                if tag == "{http://www.xbrl.org/2003/instance}xbrl":
                    self.foundInstance = True
                    self.newTree = False
                else: # break 
                    raise NotInstanceDocumentException()
            elif not tag.startswith("{http://www.xbrl.org/"):
                self.numRootFacts += 1
                if self.numRootFacts % 1000 == 0:
                    modelXbrl.profileActivity("... streaming tree check", minTimeToShow=20.0)
            self.currentEltTag = tag
        def end(self, tag):
            pass
        def data(self, data):
            pass
        def comment(self, text):
            if not self.foundInstance: # accumulate comments before xbrli:xbrl
                self.creationSoftwareComment += ('\n' if self.creationSoftwareComment else '') + text
            elif not self.creationSoftwareComment:
                self.creationSoftwareComment = text # or first comment after xbrli:xbrl
        def pi(self, target, data):
            if target == "xbrl-streamable-instance":
                if self.currentEltTag == "{http://www.xbrl.org/2003/instance}xbrl":
                    self.streamingAspects = dict(etree.PI(target,data).attrib.copy()) # dereference target results
                else:
                    modelXbrl.error("streamingExtensions:headerMisplaced",
                            _("Header is misplaced: %(target)s, must follow xbrli:xbrl element but was found at %(element)s"),
                            modelObject=modelXbrl, target=target, element=self.currentEltTag)
        def close(self):
            if not self.creationSoftwareComment:
                self.creationSoftwareComment = None
            return True
    instInfo = instInfoTarget()
    infoParser = etree.XMLParser(recover=True, huge_tree=True, target=instInfo)
    try:
        etree.parse(_file, parser=infoParser, base_url=filepath)
    except NotInstanceDocumentException:
        pass
    '''
    foundErrors = False
    foundInstance = False
    streamingAspects = None
    creationSoftwareComment = None
    instInfoNumRootFacts = 0
    numElts = 0
    elt = None
    instInfoContext = etree.iterparse(_file,
                                      events=("start", "end"),
                                      huge_tree=True)
    try:
        for event, elt in instInfoContext:
            if event == "start":
                if elt.getparent() is not None:
                    if elt.getparent(
                    ).tag == "{http://www.xbrl.org/2003/instance}xbrl":
                        if not foundInstance:
                            foundInstance = True
                            pi = precedingProcessingInstruction(
                                elt, "xbrl-streamable-instance")
                            if pi is None:
                                break
                            else:
                                streamingAspects = dict(pi.attrib.copy())
                                if creationSoftwareComment is None:
                                    creationSoftwareComment = precedingComment(
                                        elt)
                        if not elt.tag.startswith("{http://www.xbrl.org/"):
                            instInfoNumRootFacts += 1
                            if instInfoNumRootFacts % 1000 == 0:
                                modelXbrl.profileActivity(
                                    "... streaming tree check",
                                    minTimeToShow=20.0)
                    elif not foundInstance:
                        break
                elif elt.tag == "{http://www.xbrl.org/2003/instance}xbrl":
                    creationSoftwareComment = precedingComment(elt)
                    if precedingProcessingInstruction(
                            elt, "xbrl-streamable-instance") is not None:
                        modelXbrl.error(
                            "streamingExtensions:headerMisplaced",
                            _("Header is misplaced: %(error)s, must follow xbrli:xbrl element"
                              ),
                            modelObject=elt)
            elif event == "end":
                elt.clear()
                numElts += 1
                if numElts % 1000 == 0 and elt.getparent() is not None:
                    while elt.getprevious() is not None and elt.getparent(
                    ) is not None:
                        del elt.getparent()[0]
    except etree.XMLSyntaxError as err:
        modelXbrl.error("xmlSchema:syntax",
                        _("Unrecoverable error: %(error)s"),
                        error=err)
        _file.close()
        return err

    _file.seek(0, io.SEEK_SET)  # allow reparsing
    if not foundInstance or streamingAspects is None:
        del elt
        _file.close()
        return None
    modelXbrl.profileStat(_("streaming tree check"), time.time() - startedAt)
    startedAt = time.time()
    try:
        version = Decimal(streamingAspects.get("version"))
        if int(version) != 1:
            modelXbrl.error(
                "streamingExtensions:unsupportedVersion",
                _("Streaming version %(version)s, major version number must be 1"
                  ),
                modelObject=elt,
                version=version)
            foundErrors = True
    except (InvalidOperation, OverflowError):
        modelXbrl.error("streamingExtensions:versionError",
                        _("Version %(version)s, number must be 1.n"),
                        modelObject=elt,
                        version=streamingAspects.get("version", "(none)"))
        foundErrors = True
    for bufAspect in ("contextBuffer", "unitBuffer", "footnoteBuffer"):
        try:
            bufLimit = Decimal(streamingAspects.get(bufAspect, "INF"))
            if bufLimit < 1 or (bufLimit.is_finite() and bufLimit % 1 != 0):
                raise InvalidOperation
            elif bufAspect == "contextBuffer":
                contextBufferLimit = bufLimit
            elif bufAspect == "unitBuffer":
                unitBufferLimit = bufLimit
            elif bufAspect == "footnoteBuffer":
                footnoteBufferLimit = bufLimit
        except InvalidOperation:
            modelXbrl.error(
                "streamingExtensions:valueError",
                _("Streaming %(attrib)s %(value)s, number must be a positive integer or INF"
                  ),
                modelObject=elt,
                attrib=bufAspect,
                value=streamingAspects.get(bufAspect))
            foundErrors = True
    if _streamingExtensionsValidate:
        incompatibleValidations = []
        _validateDisclosureSystem = modelXbrl.modelManager.validateDisclosureSystem
        _disclosureSystem = modelXbrl.modelManager.disclosureSystem
        if _validateDisclosureSystem and _disclosureSystem.validationType == "EFM":
            incompatibleValidations.append("EFM")
        if _validateDisclosureSystem and _disclosureSystem.validationType == "GFM":
            incompatibleValidations.append("GFM")
        if _validateDisclosureSystem and _disclosureSystem.validationType == "HMRC":
            incompatibleValidations.append("HMRC")
        if modelXbrl.modelManager.validateCalcLB:
            incompatibleValidations.append("calculation LB")
        if incompatibleValidations:
            modelXbrl.error(
                "streamingExtensions:incompatibleValidation",
                _("Streaming instance validation does not support %(incompatibleValidations)s validation"
                  ),
                modelObject=modelXbrl,
                incompatibleValidations=', '.join(incompatibleValidations))
            foundErrors = True
    if instInfoContext.error_log:
        foundErrors = True
    logSyntaxErrors(instInfoContext)
    del instInfoContext  # dereference

    for pluginMethod in pluginClassMethods("Streaming.BlockStreaming"):
        _blockingPluginName = pluginMethod(modelXbrl)
        if _blockingPluginName:  # name of blocking plugin is returned
            modelXbrl.error(
                "streamingExtensions:incompatiblePlugIn",
                _("Streaming instance not supported by plugin %(blockingPlugin)s"
                  ),
                modelObject=modelXbrl,
                blockingPlugin=_blockingPluginName)
            foundErrors = True

    if foundErrors:
        _file.close()
        return None

    _encoding = XmlUtil.encoding(_file.read(512))
    _file.seek(0, io.SEEK_SET)  # allow reparsing

    if _streamingExtensionsValidate:
        validator = Validate(modelXbrl)
        instValidator = validator.instValidator

    contextBuffer = []
    contextsToDrop = []
    unitBuffer = []
    unitsToDrop = []
    footnoteBuffer = []
    footnoteLinksToDrop = []

    _streamingFactsPlugin = any(
        True for pluginMethod in pluginClassMethods("Streaming.Facts"))
    _streamingValidateFactsPlugin = (_streamingExtensionsValidate and any(
        True
        for pluginMethod in pluginClassMethods("Streaming.ValidateFacts")))
    ''' this is very much slower than iterparse
    class modelLoaderTarget():
        def __init__(self, element_factory=None, parser=None):
            self.newTree = True
            self.currentMdlObj = None
            self.beforeInstanceStream = True
            self.beforeStartStreamingPlugin = True
            self.numRootFacts = 1
            modelXbrl.makeelementParentModelObject = None
            modelXbrl.isStreamingMode = True
            self.factsCheckVersion = None
            self.factsCheckMd5s = Md5Sum()
        def start(self, tag, attrib, nsmap=None):
            modelXbrl.makeelementParentModelObject = self.currentMdlObj # pass parent to makeelement for ModelObjectFactory
            mdlObj = _parser.makeelement(tag, attrib=attrib, nsmap=nsmap)
            mdlObj.sourceline = 1
            if self.newTree:
                self.newTree = False
                self.currentMdlObj = mdlObj
                modelDocument = ModelDocument(modelXbrl, Type.INSTANCE, mappedUri, filepath, mdlObj.getroottree())
                modelXbrl.modelDocument = modelDocument # needed for incremental validation
                mdlObj.init(modelDocument)
                modelDocument.parser = _parser # needed for XmlUtil addChild's makeelement 
                modelDocument.parserLookupName = _parserLookupName
                modelDocument.parserLookupClass = _parserLookupClass
                modelDocument.xmlRootElement = mdlObj
                modelDocument.schemaLocationElements.add(mdlObj)
                modelDocument.documentEncoding = _encoding
                modelDocument._creationSoftwareComment = creationSoftwareComment
                modelXbrl.info("streamingExtensions:streaming",
                               _("Stream processing this instance."),
                               modelObject = modelDocument)
            else:
                self.currentMdlObj.append(mdlObj)
                self.currentMdlObj = mdlObj
                mdlObj._init()
                ns = mdlObj.namespaceURI
                ln = mdlObj.localName
                if (self.beforeInstanceStream and (
                    (ns == XbrlConst.link and ln not in ("schemaRef", "linkbaseRef")) or
                    (ns == XbrlConst.xbrli and ln in ("context", "unit")) or
                    (ns not in (XbrlConst.link, XbrlConst.xbrli)))):
                    self.beforeInstanceStream = False
                    if _streamingExtensionsValidate:
                        instValidator.validate(modelXbrl, modelXbrl.modelManager.formulaOptions.typedParameters(modelXbrl.prefixedNamespaces))
                    else: # need default dimensions
                        ValidateXbrlDimensions.loadDimensionDefaults(modelXbrl)
                elif not self.beforeInstanceStream and self.beforeStartStreamingPlugin:
                    for pluginMethod in pluginClassMethods("Streaming.Start"):
                        pluginMethod(modelXbrl)
                    self.beforeStartStreamingPlugin = False
            return mdlObj
        def end(self, tag):
            modelDocument = modelXbrl.modelDocument
            mdlObj = self.currentMdlObj
            parentMdlObj = mdlObj.getparent()
            self.currentMdlObj = parentMdlObj
            ns = mdlObj.namespaceURI
            ln = mdlObj.localName
            if ns == XbrlConst.xbrli:
                if ln == "context":
                    if mdlObj.get("sticky"):
                        del mdlObj.attrib["sticky"]
                        XmlValidate.validate(modelXbrl, mdlObj)
                        modelDocument.contextDiscover(mdlObj)
                    else:
                        if _streamingExtensionsValidate and len(contextBuffer) >= contextBufferLimit:
                            # drop before adding as dropped may have same id as added
                            cntx = contextBuffer.pop(0)
                            if _streamingValidateFactsPlugin:
                                contextsToDrop.append(cntx)
                            else:
                                dropContext(modelXbrl, cntx)
                                del parentMdlObj[parentMdlObj.index(cntx)]
                            cntx = None
                        #>>XmlValidate.validate(modelXbrl, mdlObj)
                        #>>modelDocument.contextDiscover(mdlObj)
                        if contextBufferLimit.is_finite():
                            contextBuffer.append(mdlObj)
                    if _streamingExtensionsValidate:
                        contextsToCheck = (mdlObj,)
                        instValidator.checkContexts(contextsToCheck)
                        if modelXbrl.hasXDT:
                            instValidator.checkContextsDimensions(contextsToCheck)
                        del contextsToCheck # dereference
                elif ln == "unit":
                    if _streamingExtensionsValidate and len(unitBuffer) >= unitBufferLimit:
                        # drop before adding as dropped may have same id as added
                        unit = unitBuffer.pop(0)
                        if _streamingValidateFactsPlugin:
                            unitsToDrop.append(unit)
                        else:
                            dropUnit(modelXbrl, unit)
                            del parentMdlObj[parentMdlObj.index(unit)]
                        unit = None 
                    #>>XmlValidate.validate(modelXbrl, mdlObj)
                    #>>modelDocument.unitDiscover(mdlObj)
                    if unitBufferLimit.is_finite():
                        unitBuffer.append(mdlObj)
                    if _streamingExtensionsValidate:
                        instValidator.checkUnits( (mdlObj,) )
                elif ln == "xbrl": # end of document
                    # check remaining batched facts if any
                    if _streamingValidateFactsPlugin:
                        # plugin attempts to process batch of all root facts not yet processed (not just current one)
                        # finish any final batch of facts
                        if len(modelXbrl.facts) > 0:
                            factsToCheck = modelXbrl.facts.copy()
                            factsHaveBeenProcessed = True
                            # can block facts deletion if required data not yet available, such as numeric unit for DpmDB
                            for pluginMethod in pluginClassMethods("Streaming.ValidateFacts"):
                                if not pluginMethod(modelXbrl, factsToCheck):
                                    factsHaveBeenProcessed = False
                            if factsHaveBeenProcessed:
                                for fact in factsToCheck:
                                    dropFact(modelXbrl, fact, modelXbrl.facts)
                                    del parentMdlObj[parentMdlObj.index(fact)]
                                for cntx in contextsToDrop:
                                    dropContext(modelXbrl, cntx)
                                    del parentMdlObj[parentMdlObj.index(cntx)]
                                for unit in unitsToDrop:
                                    dropUnit(modelXbrl, unit)
                                    del parentMdlObj[parentMdlObj.index(unit)]
                                for footnoteLink in footnoteLinksToDrop:
                                    dropFootnoteLink(modelXbrl, footnoteLink)
                                    del parentMdlObj[parentMdlObj.index(footnoteLink)]
                                fact = cntx = unit = footnoteLink = None
                                del contextsToDrop[:]
                                del unitsToDrop[:]
                                del footnoteLinksToDrop[:]
                            del factsToCheck
                    # check remaining footnote refs
                    for footnoteLink in footnoteBuffer:
                        checkFootnoteHrefs(modelXbrl, footnoteLink)
                    for pluginMethod in pluginClassMethods("Streaming.Finish"):
                        pluginMethod(modelXbrl)
            elif ns == XbrlConst.link:
                if ln == "footnoteLink":
                    XmlValidate.validate(modelXbrl, mdlObj)
                    footnoteLinks = (mdlObj,)
                    modelDocument.linkbaseDiscover(footnoteLinks, inInstance=True)
                    if footnoteBufferLimit.is_finite():
                        footnoteBuffer.append(mdlObj)
                    if _streamingExtensionsValidate:
                        instValidator.checkLinks(footnoteLinks)
                        if len(footnoteBuffer) > footnoteBufferLimit:
                            # check that hrefObjects for locators were all satisfied
                                # drop before addition as dropped may have same id as added
                            footnoteLink = footnoteBuffer.pop(0)
                            checkFootnoteHrefs(modelXbrl, footnoteLink)
                            if _streamingValidateFactsPlugin:
                                footnoteLinksToDrop.append(footnoteLink)
                            else:
                                dropFootnoteLink(modelXbrl, footnoteLink)
                                del parentMdlObj[parentMdlObj.index(footnoteLink)]
                            footnoteLink = None
                    footnoteLinks = None
                elif ln in ("schemaRef", "linkbaseRef"):
                    modelDocument.discoverHref(mdlObj)
                elif not modelXbrl.skipDTS:
                    if ln in ("roleRef", "arcroleRef"):
                        modelDocument.linkbaseDiscover((mdlObj,), inInstance=True)
            elif parentMdlObj.qname == XbrlConst.qnXbrliXbrl:
                self.numRootFacts += 1
                #>>XmlValidate.validate(modelXbrl, mdlObj)
                #>>modelDocument.factDiscover(mdlObj, modelXbrl.facts)
                if self.factsCheckVersion:
                    self.factCheckFact(mdlObj)
                if _streamingExtensionsValidate or _streamingValidateFactsPlugin:
                    factsToCheck = (mdlObj,)  # validate current fact by itself
                    if _streamingExtensionsValidate:
                        instValidator.checkFacts(factsToCheck)
                        if modelXbrl.hasXDT:
                            instValidator.checkFactsDimensions(factsToCheck)
                    if _streamingValidateFactsPlugin:
                        # plugin attempts to process batch of all root facts not yet processed (not just current one)
                        # use batches of 1000 facts
                        if len(modelXbrl.facts) > 1000:
                            factsToCheck = modelXbrl.facts.copy()
                            factsHaveBeenProcessed = True
                            # can block facts deletion if required data not yet available, such as numeric unit for DpmDB
                            for pluginMethod in pluginClassMethods("Streaming.ValidateFacts"):
                                if not pluginMethod(modelXbrl, factsToCheck):
                                    factsHaveBeenProcessed = False
                            if factsHaveBeenProcessed:
                                for fact in factsToCheck:
                                    dropFact(modelXbrl, fact, modelXbrl.facts)
                                    del parentMdlObj[parentMdlObj.index(fact)]
                                for cntx in contextsToDrop:
                                    dropContext(modelXbrl, cntx)
                                    del parentMdlObj[parentMdlObj.index(cntx)]
                                for unit in unitsToDrop:
                                    dropUnit(modelXbrl, unit)
                                    del parentMdlObj[parentMdlObj.index(unit)]
                                for footnoteLink in footnoteLinksToDrop:
                                    dropFootnoteLink(modelXbrl, footnoteLink)
                                    del parentMdlObj[parentMdlObj.index(footnoteLink)]
                                fact = cntx = unit = footnoteLink = None
                                del contextsToDrop[:]
                                del unitsToDrop[:]
                                del footnoteLinksToDrop[:]
                            del factsToCheck # dereference fact or batch of facts
                    else:
                        dropFact(modelXbrl, mdlObj, modelXbrl.facts) # single fact has been processed
                        del parentMdlObj[parentMdlObj.index(mdlObj)]
                if self.numRootFacts % 1000 == 0:
                    pass
                    #modelXbrl.profileActivity("... streaming fact {0} of {1} {2:.2f}%".format(self.numRootFacts, instInfoNumRootFacts, 
                    #                                                                          100.0 * self.numRootFacts / instInfoNumRootFacts), 
                    #                          minTimeToShow=20.0)
                    gc.collect()
                    sys.stdout.write ("\rAt fact {} of {} mem {}".format(self.numRootFacts, instInfoNumRootFacts, modelXbrl.modelManager.cntlr.memoryUsed))
            return mdlObj
        def data(self, data):
            self.currentMdlObj.text = data
        def comment(self, text):
            pass
        def pi(self, target, data):
            if target == "xbrl-facts-check":
                _match = re.search("([\\w-]+)=[\"']([^\"']+)[\"']", data)
                if _match:
                    _matchGroups = _match.groups()
                    if len(_matchGroups) == 2:
                        if _matchGroups[0] == "version":
                            self.factsCheckVersion = _matchGroups[1]
                        elif _matchGroups[0] == "sum-of-fact-md5s":
                            try:
                                expectedMd5 = Md5Sum(_matchGroups[1])
                                if self.factsCheckMd5s != expectedMd5:
                                    modelXbrl.warning("streamingExtensions:xbrlFactsCheckWarning",
                                            _("XBRL facts sum of md5s expected %(expectedMd5)s not matched to actual sum %(actualMd5Sum)s"),
                                            modelObject=modelXbrl, expectedMd5=expectedMd5, actualMd5Sum=self.factsCheckMd5s)
                                else:
                                    modelXbrl.info("info",
                                            _("Successful XBRL facts sum of md5s."),
                                            modelObject=modelXbrl)
                            except ValueError:
                                modelXbrl.error("streamingExtensions:xbrlFactsCheckError",
                                        _("Invalid sum-of-md5s %(sumOfMd5)s"),
                                        modelObject=modelXbrl, sumOfMd5=_matchGroups[1])
        def close(self):
            del modelXbrl.makeelementParentModelObject
            return None
        
        def factCheckFact(self, fact):
            self.factsCheckMd5s += fact.md5sum
            for _tupleFact in fact.modelTupleFacts:
                self.factCheckFact(_tupleFact)
        
    _parser, _parserLookupName, _parserLookupClass = parser(modelXbrl, filepath, target=modelLoaderTarget())
    etree.parse(_file, parser=_parser, base_url=filepath)
    logSyntaxErrors(_parser)
    '''
    # replace modelLoaderTarget with iterparse (as it now supports CustomElementClassLookup)
    streamingParserContext = etree.iterparse(_file,
                                             events=("start", "end"),
                                             huge_tree=True)
    from arelle.ModelObjectFactory import setParserElementClassLookup
    modelXbrl.isStreamingMode = True  # must be set before setting element class lookup
    (_parser, _parserLookupName,
     _parserLookupClass) = setParserElementClassLookup(streamingParserContext,
                                                       modelXbrl)
    foundInstance = False
    beforeInstanceStream = beforeStartStreamingPlugin = True
    numRootFacts = 0
    factsCheckVersion = None

    def factCheckFact(fact):
        modelDocument._factsCheckMd5s += fact.md5sum
        for _tupleFact in fact.modelTupleFacts:
            factCheckFact(_tupleFact)

    for event, mdlObj in streamingParserContext:
        if event == "start":
            if mdlObj.tag == "{http://www.xbrl.org/2003/instance}xbrl":
                modelDocument = ModelDocument(modelXbrl, Type.INSTANCE,
                                              mappedUri, filepath,
                                              mdlObj.getroottree())
                modelXbrl.modelDocument = modelDocument  # needed for incremental validation
                mdlObj.init(modelDocument)
                modelDocument.parser = _parser  # needed for XmlUtil addChild's makeelement
                modelDocument.parserLookupName = _parserLookupName
                modelDocument.parserLookupClass = _parserLookupClass
                modelDocument.xmlRootElement = mdlObj
                modelDocument.schemaLocationElements.add(mdlObj)
                modelDocument.documentEncoding = _encoding
                modelDocument._creationSoftwareComment = precedingComment(
                    mdlObj)
                modelDocument._factsCheckMd5s = Md5Sum()
                modelXbrl.info("streamingExtensions:streaming",
                               _("Stream processing this instance."),
                               modelObject=modelDocument)
            elif mdlObj.getparent() is not None:
                mdlObj._init()  # requires discovery as part of start elements
                if mdlObj.getparent(
                ).tag == "{http://www.xbrl.org/2003/instance}xbrl":
                    if not foundInstance:
                        foundInstance = True
                        pi = precedingProcessingInstruction(
                            mdlObj, "xbrl-facts-check")
                        if pi is not None:
                            factsCheckVersion = pi.attrib.get("version", None)
                elif not foundInstance:
                    break
                ns = mdlObj.qname.namespaceURI
                ln = mdlObj.qname.localName
                if beforeInstanceStream:
                    if ((ns == XbrlConst.link
                         and ln not in ("schemaRef", "linkbaseRef")) or
                        (ns == XbrlConst.xbrli and ln in ("context", "unit"))
                            or (ns not in (XbrlConst.link, XbrlConst.xbrli))):
                        beforeInstanceStream = False
                        if _streamingExtensionsValidate:
                            instValidator.validate(
                                modelXbrl,
                                modelXbrl.modelManager.formulaOptions.
                                typedParameters(modelXbrl.prefixedNamespaces))
                        else:  # need default dimensions
                            ValidateXbrlDimensions.loadDimensionDefaults(
                                modelXbrl)
                elif not beforeInstanceStream and beforeStartStreamingPlugin:
                    for pluginMethod in pluginClassMethods("Streaming.Start"):
                        pluginMethod(modelXbrl)
                    beforeStartStreamingPlugin = False
        elif event == "end":
            parentMdlObj = mdlObj.getparent()
            ns = mdlObj.namespaceURI
            ln = mdlObj.localName
            if ns == XbrlConst.xbrli:
                if ln == "context":
                    if mdlObj.get("sticky"):
                        del mdlObj.attrib["sticky"]
                        XmlValidate.validate(modelXbrl, mdlObj)
                        modelDocument.contextDiscover(mdlObj)
                    else:
                        if len(contextBuffer) >= contextBufferLimit:
                            # drop before adding as dropped may have same id as added
                            cntx = contextBuffer.pop(0)
                            if _streamingFactsPlugin or _streamingValidateFactsPlugin:
                                contextsToDrop.append(cntx)
                            else:
                                dropContext(modelXbrl, cntx)
                                #>>del parentMdlObj[parentMdlObj.index(cntx)]
                            cntx = None
                        XmlValidate.validate(modelXbrl, mdlObj)
                        modelDocument.contextDiscover(mdlObj)
                        if contextBufferLimit.is_finite():
                            contextBuffer.append(mdlObj)
                    if _streamingExtensionsValidate:
                        contextsToCheck = (mdlObj, )
                        instValidator.checkContexts(contextsToCheck)
                        if modelXbrl.hasXDT:
                            instValidator.checkContextsDimensions(
                                contextsToCheck)
                        del contextsToCheck  # dereference
                elif ln == "unit":
                    if len(unitBuffer) >= unitBufferLimit:
                        # drop before additing as dropped may have same id as added
                        unit = unitBuffer.pop(0)
                        if _streamingFactsPlugin or _streamingValidateFactsPlugin:
                            unitsToDrop.append(unit)
                        else:
                            dropUnit(modelXbrl, unit)
                            #>>del parentMdlObj[parentMdlObj.index(unit)]
                        unit = None
                    XmlValidate.validate(modelXbrl, mdlObj)
                    modelDocument.unitDiscover(mdlObj)
                    if unitBufferLimit.is_finite():
                        unitBuffer.append(mdlObj)
                    if _streamingExtensionsValidate:
                        instValidator.checkUnits((mdlObj, ))
                elif ln == "xbrl":  # end of document
                    # check remaining batched facts if any
                    if _streamingFactsPlugin or _streamingValidateFactsPlugin:
                        # plugin attempts to process batch of all root facts not yet processed (not just current one)
                        # finish any final batch of facts
                        if len(modelXbrl.facts) > 0:
                            factsToCheck = modelXbrl.facts.copy()
                            # can block facts deletion if required data not yet available, such as numeric unit for DpmDB
                            if _streamingValidateFactsPlugin:
                                for pluginMethod in pluginClassMethods(
                                        "Streaming.ValidateFacts"):
                                    pluginMethod(instValidator, factsToCheck)
                            if _streamingFactsPlugin:
                                for pluginMethod in pluginClassMethods(
                                        "Streaming.Facts"):
                                    pluginMethod(modelXbrl, factsToCheck)
                            for fact in factsToCheck:
                                dropFact(modelXbrl, fact, modelXbrl.facts)
                                #>>del parentMdlObj[parentMdlObj.index(fact)]
                            for cntx in contextsToDrop:
                                dropContext(modelXbrl, cntx)
                                #>>del parentMdlObj[parentMdlObj.index(cntx)]
                            for unit in unitsToDrop:
                                dropUnit(modelXbrl, unit)
                                #>>del parentMdlObj[parentMdlObj.index(unit)]
                            for footnoteLink in footnoteLinksToDrop:
                                dropFootnoteLink(modelXbrl, footnoteLink)
                                #>>del parentMdlObj[parentMdlObj.index(footnoteLink)]
                            fact = cntx = unit = footnoteLink = None
                            del contextsToDrop[:]
                            del unitsToDrop[:]
                            del footnoteLinksToDrop[:]
                            del factsToCheck
                    # check remaining footnote refs
                    for footnoteLink in footnoteBuffer:
                        checkFootnoteHrefs(modelXbrl, footnoteLink)
                    pi = childProcessingInstruction(mdlObj,
                                                    "xbrl-facts-check",
                                                    reversed=True)
                    if pi is not None:  # attrib is in .text, not attrib, no idea why!!!
                        _match = re.search("([\\w-]+)=[\"']([^\"']+)[\"']",
                                           pi.text)
                        if _match:
                            _matchGroups = _match.groups()
                            if len(_matchGroups) == 2:
                                if _matchGroups[0] == "sum-of-fact-md5s":
                                    try:
                                        expectedMd5 = Md5Sum(_matchGroups[1])
                                        if modelDocument._factsCheckMd5s != expectedMd5:
                                            modelXbrl.warning(
                                                "streamingExtensions:xbrlFactsCheckWarning",
                                                _("XBRL facts sum of md5s expected %(expectedMd5)s not matched to actual sum %(actualMd5Sum)s"
                                                  ),
                                                modelObject=modelXbrl,
                                                expectedMd5=expectedMd5,
                                                actualMd5Sum=modelDocument.
                                                _factsCheckMd5s)
                                        else:
                                            modelXbrl.info(
                                                "info",
                                                _("Successful XBRL facts sum of md5s."
                                                  ),
                                                modelObject=modelXbrl)
                                    except ValueError:
                                        modelXbrl.error(
                                            "streamingExtensions:xbrlFactsCheckError",
                                            _("Invalid sum-of-md5s %(sumOfMd5)s"
                                              ),
                                            modelObject=modelXbrl,
                                            sumOfMd5=_matchGroups[1])
                    if _streamingValidateFactsPlugin:
                        for pluginMethod in pluginClassMethods(
                                "Streaming.ValidateFinish"):
                            pluginMethod(instValidator)
                    if _streamingFactsPlugin:
                        for pluginMethod in pluginClassMethods(
                                "Streaming.Finish"):
                            pluginMethod(modelXbrl)
            elif ns == XbrlConst.link:
                if ln in ("schemaRef", "linkbaseRef"):
                    modelDocument.discoverHref(
                        mdlObj,
                        urlRewritePluginClass=
                        "ModelDocument.InstanceSchemaRefRewriter")
                elif ln in ("roleRef", "arcroleRef"):
                    modelDocument.linkbaseDiscover((mdlObj, ), inInstance=True)
                elif ln == "footnoteLink":
                    XmlValidate.validate(modelXbrl, mdlObj)
                    footnoteLinks = (mdlObj, )
                    modelDocument.linkbaseDiscover(footnoteLinks,
                                                   inInstance=True)
                    if footnoteBufferLimit.is_finite():
                        footnoteBuffer.append(mdlObj)
                    if _streamingExtensionsValidate:
                        instValidator.checkLinks(footnoteLinks)
                        if len(footnoteBuffer) > footnoteBufferLimit:
                            # check that hrefObjects for locators were all satisfied
                            # drop before addition as dropped may have same id as added
                            footnoteLink = footnoteBuffer.pop(0)
                            checkFootnoteHrefs(modelXbrl, footnoteLink)
                            if _streamingValidateFactsPlugin:
                                footnoteLinksToDrop.append(footnoteLink)
                            else:
                                dropFootnoteLink(modelXbrl, footnoteLink)
                                #>>del parentMdlObj[parentMdlObj.index(footnoteLink)]
                            footnoteLink = None
                    footnoteLinks = None
            elif parentMdlObj.qname == XbrlConst.qnXbrliXbrl and isinstance(
                    mdlObj, ModelFact):
                numRootFacts += 1
                XmlValidate.validate(modelXbrl, mdlObj)
                modelDocument.factDiscover(mdlObj, modelXbrl.facts)
                if factsCheckVersion:
                    factCheckFact(mdlObj)
                if _streamingExtensionsValidate or _streamingFactsPlugin or _streamingValidateFactsPlugin:
                    factsToCheck = (mdlObj,
                                    )  # validate current fact by itself
                    if _streamingExtensionsValidate:
                        instValidator.checkFacts(factsToCheck)
                        if modelXbrl.hasXDT:
                            instValidator.checkFactsDimensions(factsToCheck)
                    if _streamingFactsPlugin or _streamingValidateFactsPlugin:
                        # plugin attempts to process batch of all root facts not yet processed (not just current one)
                        # use batches of 1000 facts
                        if len(modelXbrl.facts) > 1000:
                            factsToCheck = modelXbrl.facts.copy()
                            # can block facts deletion if required data not yet available, such as numeric unit for DpmDB
                            if _streamingValidateFactsPlugin:
                                for pluginMethod in pluginClassMethods(
                                        "Streaming.ValidateFacts"):
                                    pluginMethod(instValidator, factsToCheck)
                            if _streamingFactsPlugin:
                                for pluginMethod in pluginClassMethods(
                                        "Streaming.Facts"):
                                    pluginMethod(modelXbrl, factsToCheck)
                            for fact in factsToCheck:
                                dropFact(modelXbrl, fact, modelXbrl.facts)
                                #>>del parentMdlObj[parentMdlObj.index(fact)]
                            for cntx in contextsToDrop:
                                dropContext(modelXbrl, cntx)
                                #>>del parentMdlObj[parentMdlObj.index(cntx)]
                            for unit in unitsToDrop:
                                dropUnit(modelXbrl, unit)
                                #>>del parentMdlObj[parentMdlObj.index(unit)]
                            for footnoteLink in footnoteLinksToDrop:
                                dropFootnoteLink(modelXbrl, footnoteLink)
                                #>>del parentMdlObj[parentMdlObj.index(footnoteLink)]
                            fact = cntx = unit = footnoteLink = None
                            del contextsToDrop[:]
                            del unitsToDrop[:]
                            del footnoteLinksToDrop[:]
                            del factsToCheck  # dereference fact or batch of facts
                    else:
                        dropFact(
                            modelXbrl, mdlObj,
                            modelXbrl.facts)  # single fact has been processed
                        #>>del parentMdlObj[parentMdlObj.index(mdlObj)]
                if numRootFacts % 1000 == 0:
                    pass
                    #modelXbrl.profileActivity("... streaming fact {0} of {1} {2:.2f}%".format(self.numRootFacts, instInfoNumRootFacts,
                    #                                                                          100.0 * self.numRootFacts / instInfoNumRootFacts),
                    #                          minTimeToShow=20.0)
                    #gc.collect()
                    #sys.stdout.write ("\rAt fact {} of {} mem {}".format(numRootFacts, instInfoNumRootFacts, modelXbrl.modelManager.cntlr.memoryUsed))
    if mdlObj is not None:
        mdlObj.clear()
    del _parser, _parserLookupName, _parserLookupClass

    if _streamingExtensionsValidate and validator is not None:
        _file.close()
        del instValidator
        validator.close()
        # track that modelXbrl has been validated by this streaming extension
        modelXbrl._streamingExtensionValidated = True

    modelXbrl.profileStat(_("streaming complete"), time.time() - startedAt)
    return modelXbrl.modelDocument
Exemple #49
0
 def urls(self):
     _urls = [os.path.join(self.modelManager.cntlr.configDir, "disclosuresystems.xml")]
     # get custom config xml file url, insert before main url in reverse order
     for pluginXbrlMethod in pluginClassMethods("DisclosureSystem.ConfigURL"):
         _urls.insert(0, pluginXbrlMethod(self))
     return _urls
Exemple #50
0
    def validateTestcase(self, testcase):
        self.modelXbrl.info("info", "Testcase", modelDocument=testcase)
        self.modelXbrl.viewModelObject(testcase.objectId())
        if testcase.type in (Type.TESTCASESINDEX, Type.REGISTRY):
            for doc in sorted(testcase.referencesDocument.keys(), key=lambda doc: doc.uri):
                self.validateTestcase(doc)  # testcases doc's are sorted by their uri (file names), e.g., for formula
        elif hasattr(testcase, "testcaseVariations"):
            for modelTestcaseVariation in testcaseVariationsByTarget(testcase.testcaseVariations):
                # update ui thread via modelManager (running in background here)
                self.modelXbrl.modelManager.viewModelObject(self.modelXbrl, modelTestcaseVariation.objectId())
                # is this a versioning report?
                resultIsVersioningReport = modelTestcaseVariation.resultIsVersioningReport
                resultIsXbrlInstance = modelTestcaseVariation.resultIsXbrlInstance
                resultIsTaxonomyPackage = modelTestcaseVariation.resultIsTaxonomyPackage
                formulaOutputInstance = None
                inputDTSes = defaultdict(list)
                baseForElement = testcase.baseForElement(modelTestcaseVariation)
                # try to load instance document
                self.modelXbrl.info("info", _("Variation %(id)s%(name)s%(target)s: %(expected)s - %(description)s"),
                                    modelObject=modelTestcaseVariation, 
                                    id=modelTestcaseVariation.id, 
                                    name=(" {}".format(modelTestcaseVariation.name) if modelTestcaseVariation.name else ""), 
                                    target=(" target {}".format(modelTestcaseVariation.ixdsTarget) if modelTestcaseVariation.ixdsTarget else ""),
                                    expected=modelTestcaseVariation.expected, 
                                    description=modelTestcaseVariation.description)
                if self.modelXbrl.modelManager.formulaOptions.testcaseResultsCaptureWarnings:
                    errorCaptureLevel = logging._checkLevel("WARNING")
                else:
                    errorCaptureLevel = modelTestcaseVariation.severityLevel # default is INCONSISTENCY
                parameters = modelTestcaseVariation.parameters.copy()
                for readMeFirstUri in modelTestcaseVariation.readMeFirstUris:
                    if isinstance(readMeFirstUri,tuple):
                        # dtsName is for formula instances, but is from/to dts if versioning
                        dtsName, readMeFirstUri = readMeFirstUri
                    elif resultIsVersioningReport:
                        if inputDTSes: dtsName = "to"
                        else: dtsName = "from"
                    else:
                        dtsName = None
                    if resultIsVersioningReport and dtsName: # build multi-schemaRef containing document
                        if dtsName in inputDTSes:
                            dtsName = inputDTSes[dtsName]
                        else:
                            modelXbrl = ModelXbrl.create(self.modelXbrl.modelManager, 
                                         Type.DTSENTRIES,
                                         self.modelXbrl.modelManager.cntlr.webCache.normalizeUrl(readMeFirstUri[:-4] + ".dts", baseForElement),
                                         isEntry=True,
                                         errorCaptureLevel=errorCaptureLevel)
                        DTSdoc = modelXbrl.modelDocument
                        DTSdoc.inDTS = True
                        doc = modelDocumentLoad(modelXbrl, readMeFirstUri, base=baseForElement)
                        if doc is not None:
                            DTSdoc.referencesDocument[doc] = ModelDocumentReference("import", DTSdoc.xmlRootElement)  #fake import
                            doc.inDTS = True
                    elif resultIsTaxonomyPackage:
                        from arelle import PackageManager, PrototypeInstanceObject
                        dtsName = readMeFirstUri
                        modelXbrl = PrototypeInstanceObject.XbrlPrototype(self.modelXbrl.modelManager, readMeFirstUri)
                        PackageManager.packageInfo(self.modelXbrl.modelManager.cntlr, readMeFirstUri, reload=True, errors=modelXbrl.errors)
                    else: # not a multi-schemaRef versioning report
                        if self.useFileSource.isArchive:
                            modelXbrl = ModelXbrl.load(self.modelXbrl.modelManager, 
                                                       readMeFirstUri,
                                                       _("validating"), 
                                                       base=baseForElement,
                                                       useFileSource=self.useFileSource,
                                                       errorCaptureLevel=errorCaptureLevel,
                                                       ixdsTarget=modelTestcaseVariation.ixdsTarget)
                        else: # need own file source, may need instance discovery
                            filesource = FileSource.openFileSource(readMeFirstUri, self.modelXbrl.modelManager.cntlr, base=baseForElement)
                            if filesource and not filesource.selection and filesource.isArchive:
                                try:
                                    if filesource.isTaxonomyPackage:
                                        _rptPkgIxdsOptions = {}
                                        for pluginXbrlMethod in pluginClassMethods("ModelTestcaseVariation.ReportPackageIxdsOptions"):
                                            pluginXbrlMethod(self, _rptPkgIxdsOptions)
                                        filesource.loadTaxonomyPackageMappings()
                                        for pluginXbrlMethod in pluginClassMethods("ModelTestcaseVariation.ReportPackageIxds"):
                                            filesource.select(pluginXbrlMethod(filesource, **_rptPkgIxdsOptions))
                                    else:
                                        from arelle.CntlrCmdLine import filesourceEntrypointFiles
                                        entrypoints = filesourceEntrypointFiles(filesource)
                                        if entrypoints:
                                            # resolve an IXDS in entrypoints
                                            for pluginXbrlMethod in pluginClassMethods("ModelTestcaseVariation.ArchiveIxds"):
                                                pluginXbrlMethod(self, filesource,entrypoints)
                                            filesource.select(entrypoints[0].get("file", None) )
                                except Exception as err:
                                    self.modelXbrl.error("exception:" + type(err).__name__,
                                        _("Testcase variation validation exception: %(error)s, entry URL: %(instance)s"),
                                        modelXbrl=self.modelXbrl, instance=readMeFirstUri, error=err)
                                    continue # don't try to load this entry URL
                            modelXbrl = ModelXbrl.load(self.modelXbrl.modelManager, 
                                                       filesource,
                                                       _("validating"), 
                                                       base=baseForElement,
                                                       errorCaptureLevel=errorCaptureLevel,
                                                       ixdsTarget=modelTestcaseVariation.ixdsTarget)
                        modelXbrl.isTestcaseVariation = True
                    if modelXbrl.modelDocument is None:
                        modelXbrl.info("arelle:notLoaded",
                             _("Variation %(id)s %(name)s readMeFirst document not loaded: %(file)s"),
                             modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, file=os.path.basename(readMeFirstUri))
                        self.determineNotLoadedTestStatus(modelTestcaseVariation, modelXbrl.errors)
                        modelXbrl.close()
                    elif resultIsVersioningReport or resultIsTaxonomyPackage:
                        inputDTSes[dtsName] = modelXbrl
                    elif modelXbrl.modelDocument.type == Type.VERSIONINGREPORT:
                        ValidateVersReport.ValidateVersReport(self.modelXbrl).validate(modelXbrl)
                        self.determineTestStatus(modelTestcaseVariation, modelXbrl.errors)
                        modelXbrl.close()
                    elif testcase.type == Type.REGISTRYTESTCASE:
                        self.instValidator.validate(modelXbrl)  # required to set up dimensions, etc
                        self.instValidator.executeCallTest(modelXbrl, modelTestcaseVariation.id, 
                                   modelTestcaseVariation.cfcnCall, modelTestcaseVariation.cfcnTest)
                        self.determineTestStatus(modelTestcaseVariation, modelXbrl.errors)
                        self.instValidator.close()
                        modelXbrl.close()
                    else:
                        inputDTSes[dtsName].append(modelXbrl)
                        # validate except for formulas
                        _hasFormulae = modelXbrl.hasFormulae
                        modelXbrl.hasFormulae = False
                        try:
                            for pluginXbrlMethod in pluginClassMethods("TestcaseVariation.Xbrl.Loaded"):
                                pluginXbrlMethod(self.modelXbrl, modelXbrl, modelTestcaseVariation)
                            self.instValidator.validate(modelXbrl, parameters)
                            for pluginXbrlMethod in pluginClassMethods("TestcaseVariation.Xbrl.Validated"):
                                pluginXbrlMethod(self.modelXbrl, modelXbrl)
                        except Exception as err:
                            modelXbrl.error("exception:" + type(err).__name__,
                                _("Testcase variation validation exception: %(error)s, instance: %(instance)s"),
                                modelXbrl=modelXbrl, instance=modelXbrl.modelDocument.basename, error=err, exc_info=(type(err) is not AssertionError))
                        modelXbrl.hasFormulae = _hasFormulae
                if resultIsVersioningReport and modelXbrl.modelDocument:
                    versReportFile = modelXbrl.modelManager.cntlr.webCache.normalizeUrl(
                        modelTestcaseVariation.versioningReportUri, baseForElement)
                    if os.path.exists(versReportFile): #validate existing
                        modelVersReport = ModelXbrl.load(self.modelXbrl.modelManager, versReportFile, _("validating existing version report"))
                        if modelVersReport and modelVersReport.modelDocument and modelVersReport.modelDocument.type == Type.VERSIONINGREPORT:
                            ValidateVersReport.ValidateVersReport(self.modelXbrl).validate(modelVersReport)
                            self.determineTestStatus(modelTestcaseVariation, modelVersReport.errors)
                            modelVersReport.close()
                    elif len(inputDTSes) == 2:
                        ModelVersReport.ModelVersReport(self.modelXbrl).diffDTSes(
                              versReportFile, inputDTSes["from"], inputDTSes["to"])
                        modelTestcaseVariation.status = "generated"
                    else:
                        modelXbrl.error("arelle:notLoaded",
                             _("Variation %(id)s %(name)s input DTSes not loaded, unable to generate versioning report: %(file)s"),
                             modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, file=os.path.basename(readMeFirstUri))
                        modelTestcaseVariation.status = "failed"
                    for inputDTS in inputDTSes.values():
                        inputDTS.close()
                    del inputDTSes # dereference
                elif resultIsTaxonomyPackage:
                    self.determineTestStatus(modelTestcaseVariation, modelXbrl.errors)
                    modelXbrl.close()
                elif inputDTSes:
                    # validate schema, linkbase, or instance
                    modelXbrl = inputDTSes[None][0]
                    expectedDataFiles = set(modelXbrl.modelManager.cntlr.webCache.normalizeUrl(uri, baseForElement)
                                            for d in modelTestcaseVariation.dataUris.values() for uri in d
                                            if not UrlUtil.isAbsolute(uri))
                    foundDataFiles = set()
                    variationBase = os.path.dirname(baseForElement)
                    for dtsName, inputDTS in inputDTSes.items():  # input instances are also parameters
                        if dtsName: # named instance
                            parameters[dtsName] = (None, inputDTS) #inputDTS is a list of modelXbrl's (instance DTSes)
                        elif len(inputDTS) > 1: # standard-input-instance with multiple instance documents
                            parameters[XbrlConst.qnStandardInputInstance] = (None, inputDTS) # allow error detection in validateFormula
                        for _inputDTS in inputDTS:
                            for docUrl, doc in _inputDTS.urlDocs.items():
                                if docUrl.startswith(variationBase) and not doc.type == Type.INLINEXBRLDOCUMENTSET:
                                    if getattr(doc,"loadedFromXbrlFormula", False): # may have been sourced from xf file
                                        if docUrl.replace("-formula.xml", ".xf") in expectedDataFiles:
                                            docUrl = docUrl.replace("-formula.xml", ".xf")
                                    foundDataFiles.add(docUrl)
                    if expectedDataFiles - foundDataFiles:
                        modelXbrl.info("arelle:testcaseDataNotUsed",
                            _("Variation %(id)s %(name)s data files not used: %(missingDataFiles)s"),
                            modelObject=modelTestcaseVariation, name=modelTestcaseVariation.name, id=modelTestcaseVariation.id, 
                            missingDataFiles=", ".join(sorted(os.path.basename(f) for f in expectedDataFiles - foundDataFiles)))
                    if foundDataFiles - expectedDataFiles:
                        modelXbrl.info("arelle:testcaseDataUnexpected",
                            _("Variation %(id)s %(name)s files not in variation data: %(unexpectedDataFiles)s"),
                            modelObject=modelTestcaseVariation, name=modelTestcaseVariation.name, id=modelTestcaseVariation.id,
                            unexpectedDataFiles=", ".join(sorted(os.path.basename(f) for f in foundDataFiles - expectedDataFiles)))
                    if modelXbrl.hasTableRendering or modelTestcaseVariation.resultIsTable:
                        try:
                            RenderingEvaluator.init(modelXbrl)
                        except Exception as err:
                            modelXbrl.error("exception:" + type(err).__name__,
                                _("Testcase RenderingEvaluator.init exception: %(error)s, instance: %(instance)s"),
                                modelXbrl=modelXbrl, instance=modelXbrl.modelDocument.basename, error=err, exc_info=True)
                    modelXbrlHasFormulae = modelXbrl.hasFormulae
                    if modelXbrlHasFormulae and self.modelXbrl.modelManager.formulaOptions.formulaAction != "none":
                        try:
                            # validate only formulae
                            self.instValidator.parameters = parameters
                            ValidateFormula.validate(self.instValidator)
                        except Exception as err:
                            modelXbrl.error("exception:" + type(err).__name__,
                                _("Testcase formula variation validation exception: %(error)s, instance: %(instance)s"),
                                modelXbrl=modelXbrl, instance=modelXbrl.modelDocument.basename, error=err, exc_info=(type(err) is not AssertionError))
                    if modelTestcaseVariation.resultIsInfoset and self.modelXbrl.modelManager.validateInfoset:
                        for pluginXbrlMethod in pluginClassMethods("Validate.Infoset"):
                            pluginXbrlMethod(modelXbrl, modelTestcaseVariation.resultInfosetUri)
                        infoset = ModelXbrl.load(self.modelXbrl.modelManager, 
                                                 modelTestcaseVariation.resultInfosetUri,
                                                   _("loading result infoset"), 
                                                   base=baseForElement,
                                                   useFileSource=self.useFileSource,
                                                   errorCaptureLevel=errorCaptureLevel)
                        if infoset.modelDocument is None:
                            modelXbrl.error("arelle:notLoaded",
                                _("Variation %(id)s %(name)s result infoset not loaded: %(file)s"),
                                modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, 
                                file=os.path.basename(modelTestcaseVariation.resultXbrlInstance))
                            modelTestcaseVariation.status = "result infoset not loadable"
                        else:   # check infoset
                            ValidateInfoset.validate(self.instValidator, modelXbrl, infoset)
                        infoset.close()
                    if modelXbrl.hasTableRendering or modelTestcaseVariation.resultIsTable: # and self.modelXbrl.modelManager.validateInfoset:
                        # diff (or generate) table infoset
                        resultTableUri = modelXbrl.modelManager.cntlr.webCache.normalizeUrl(modelTestcaseVariation.resultTableUri, baseForElement)
                        if not any(alternativeValidation(modelXbrl, resultTableUri)
                                   for alternativeValidation in pluginClassMethods("Validate.TableInfoset")):
                            try:
                                ViewFileRenderedGrid.viewRenderedGrid(modelXbrl, resultTableUri, diffToFile=True)  # false to save infoset files
                            except Exception as err:
                                modelXbrl.error("exception:" + type(err).__name__,
                                    _("Testcase table linkbase validation exception: %(error)s, instance: %(instance)s"),
                                    modelXbrl=modelXbrl, instance=modelXbrl.modelDocument.basename, error=err, exc_info=True)
                    self.instValidator.close()
                    extraErrors = []
                    for pluginXbrlMethod in pluginClassMethods("TestcaseVariation.Validated"):
                        pluginXbrlMethod(self.modelXbrl, modelXbrl, extraErrors)
                    self.determineTestStatus(modelTestcaseVariation, [e for inputDTSlist in inputDTSes.values() for inputDTS in inputDTSlist for e in inputDTS.errors] + extraErrors) # include infoset errors in status
                    if modelXbrl.formulaOutputInstance and self.noErrorCodes(modelTestcaseVariation.actual): 
                        # if an output instance is created, and no string error codes, ignoring dict of assertion results, validate it
                        modelXbrl.formulaOutputInstance.hasFormulae = False #  block formulae on output instance (so assertion of input is not lost)
                        self.instValidator.validate(modelXbrl.formulaOutputInstance, modelTestcaseVariation.parameters)
                        self.determineTestStatus(modelTestcaseVariation, modelXbrl.formulaOutputInstance.errors)
                        if self.noErrorCodes(modelTestcaseVariation.actual): # if still 'clean' pass it forward for comparison to expected result instance
                            formulaOutputInstance = modelXbrl.formulaOutputInstance
                            modelXbrl.formulaOutputInstance = None # prevent it from being closed now
                        self.instValidator.close()
                    compareIxResultInstance = (modelXbrl.modelDocument.type in (Type.INLINEXBRL, Type.INLINEXBRLDOCUMENTSET) and 
                                               modelTestcaseVariation.resultXbrlInstanceUri is not None)
                    if compareIxResultInstance:
                        formulaOutputInstance = modelXbrl # compare modelXbrl to generated output instance
                        errMsgPrefix = "ix"
                    else: # delete input instances before formula output comparision
                        for inputDTSlist in inputDTSes.values():
                            for inputDTS in inputDTSlist:
                                inputDTS.close()
                        del inputDTSes # dereference
                        errMsgPrefix = "formula"
                    if resultIsXbrlInstance and formulaOutputInstance and formulaOutputInstance.modelDocument:
                        _matchExpectedResultIDs = not modelXbrlHasFormulae # formula restuls have inconsistent IDs
                        expectedInstance = ModelXbrl.load(self.modelXbrl.modelManager, 
                                                   modelTestcaseVariation.resultXbrlInstanceUri,
                                                   _("loading expected result XBRL instance"), 
                                                   base=baseForElement,
                                                   useFileSource=self.useFileSource,
                                                   errorCaptureLevel=errorCaptureLevel)
                        if expectedInstance.modelDocument is None:
                            self.modelXbrl.error("{}:expectedResultNotLoaded".format(errMsgPrefix),
                                _("Testcase \"%(name)s\" %(id)s expected result instance not loaded: %(file)s"),
                                modelXbrl=testcase, id=modelTestcaseVariation.id, name=modelTestcaseVariation.name, 
                                file=os.path.basename(modelTestcaseVariation.resultXbrlInstanceUri),
                                messageCodes=("formula:expectedResultNotLoaded","ix:expectedResultNotLoaded"))
                            modelTestcaseVariation.status = "result not loadable"
                        else:   # compare facts
                            for pluginXbrlMethod in pluginClassMethods("TestcaseVariation.ExpectedInstance.Loaded"):
                                pluginXbrlMethod(expectedInstance, formulaOutputInstance)
                            if len(expectedInstance.facts) != len(formulaOutputInstance.facts):
                                formulaOutputInstance.error("{}:resultFactCounts".format(errMsgPrefix),
                                    _("Formula output %(countFacts)s facts, expected %(expectedFacts)s facts"),
                                    modelXbrl=modelXbrl, countFacts=len(formulaOutputInstance.facts),
                                    expectedFacts=len(expectedInstance.facts),
                                    messageCodes=("formula:resultFactCounts","ix:resultFactCounts"))
                            else:
                                formulaOutputFootnotesRelSet = ModelRelationshipSet(formulaOutputInstance, "XBRL-footnotes")
                                expectedFootnotesRelSet = ModelRelationshipSet(expectedInstance, "XBRL-footnotes")
                                def factFootnotes(fact, footnotesRelSet):
                                    footnotes = {}
                                    footnoteRels = footnotesRelSet.fromModelObject(fact)
                                    if footnoteRels:
                                        # most process rels in same order between two instances, use labels to sort
                                        for i, footnoteRel in enumerate(sorted(footnoteRels,
                                                                               key=lambda r: (r.fromLabel,r.toLabel))):
                                            modelObject = footnoteRel.toModelObject
                                            if isinstance(modelObject, ModelResource):
                                                xml = collapseWhitespace(modelObject.viewText().strip())
                                                footnotes["Footnote {}".format(i+1)] = xml #re.sub(r'\s+', ' ', collapseWhitespace(modelObject.stringValue))
                                            elif isinstance(modelObject, ModelFact):
                                                footnotes["Footnoted fact {}".format(i+1)] = \
                                                    "{} context: {} value: {}".format(
                                                    modelObject.qname,
                                                    modelObject.contextID,
                                                    collapseWhitespace(modelObject.value))
                                    return footnotes
                                for expectedInstanceFact in expectedInstance.facts:
                                    unmatchedFactsStack = []
                                    formulaOutputFact = formulaOutputInstance.matchFact(expectedInstanceFact, unmatchedFactsStack, deemP0inf=True, matchId=_matchExpectedResultIDs, matchLang=False)
                                    #formulaOutputFact = formulaOutputInstance.matchFact(expectedInstanceFact, unmatchedFactsStack, deemP0inf=True, matchId=True, matchLang=True)
                                    if formulaOutputFact is None:
                                        if unmatchedFactsStack: # get missing nested tuple fact, if possible
                                            missingFact = unmatchedFactsStack[-1]
                                        else:
                                            missingFact = expectedInstanceFact
                                        # is it possible to show value mismatches?
                                        expectedFacts = formulaOutputInstance.factsByQname.get(missingFact.qname)
                                        if len(expectedFacts) == 1:
                                            formulaOutputInstance.error("{}:expectedFactMissing".format(errMsgPrefix),
                                                _("Output missing expected fact %(fact)s, extracted value \"%(value1)s\", expected value  \"%(value2)s\""),
                                                modelXbrl=missingFact, fact=missingFact.qname, value1=missingFact.xValue, value2=next(iter(expectedFacts)).xValue,
                                                messageCodes=("formula:expectedFactMissing","ix:expectedFactMissing"))
                                        else:
                                            formulaOutputInstance.error("{}:expectedFactMissing".format(errMsgPrefix),
                                                _("Output missing expected fact %(fact)s"),
                                                modelXbrl=missingFact, fact=missingFact.qname,
                                                messageCodes=("formula:expectedFactMissing","ix:expectedFactMissing"))
                                    else: # compare footnotes
                                        expectedInstanceFactFootnotes = factFootnotes(expectedInstanceFact, expectedFootnotesRelSet)
                                        formulaOutputFactFootnotes = factFootnotes(formulaOutputFact, formulaOutputFootnotesRelSet)
                                        if (len(expectedInstanceFactFootnotes) != len(formulaOutputFactFootnotes) or
                                            set(expectedInstanceFactFootnotes.values()) != set(formulaOutputFactFootnotes.values())):
                                            formulaOutputInstance.error("{}:expectedFactFootnoteDifference".format(errMsgPrefix),
                                                _("Output expected fact %(fact)s expected footnotes %(footnotes1)s produced footnotes %(footnotes2)s"),
                                                modelXbrl=(formulaOutputFact,expectedInstanceFact), fact=expectedInstanceFact.qname, footnotes1=sorted(expectedInstanceFactFootnotes.items()), footnotes2=sorted(formulaOutputFactFootnotes.items()),
                                                messageCodes=("formula:expectedFactFootnoteDifference","ix:expectedFactFootnoteDifference"))

                            # for debugging uncomment next line to save generated instance document
                            # formulaOutputInstance.saveInstance(r"c:\temp\test-out-inst.xml")
                        expectedInstance.close()
                        del expectedInstance # dereference
                        self.determineTestStatus(modelTestcaseVariation, formulaOutputInstance.errors)
                        formulaOutputInstance.close()
                        del formulaOutputInstance
                    if compareIxResultInstance:
                        for inputDTSlist in inputDTSes.values():
                            for inputDTS in inputDTSlist:
                                inputDTS.close()
                        del inputDTSes # dereference
                # update ui thread via modelManager (running in background here)
                self.modelXbrl.modelManager.viewModelObject(self.modelXbrl, modelTestcaseVariation.objectId())
                    
            _statusCounts = OrderedDict((("pass",0),("fail",0)))
            for tv in getattr(testcase, "testcaseVariations", ()):
                _statusCounts[tv.status] = _statusCounts.get(tv.status, 0) + 1    
            self.modelXbrl.info("arelle:testCaseResults", ", ".join("{}={}".format(k,c) for k, c in _statusCounts.items() if k))
            
            self.modelXbrl.modelManager.showStatus(_("ready"), 2000)
 def expectedCount(self):
     for pluginXbrlMethod in pluginClassMethods("ModelTestcaseVariation.ExpectedCount"):
         _count = pluginXbrlMethod(self)
         if _count is not None: # ignore plug in if not a plug-in-recognized test case
             return _count
     return None
Exemple #52
0
    def viewConcept(self, concept, modelObject, labelPrefix, preferredLabel,
                    parentnode, n, relationshipSet, visited):
        if concept is None:
            return
        try:
            isRelation = isinstance(modelObject,
                                    ModelDtsObject.ModelRelationship)
            isModelTable = False
            filingIndicatorCode = ""
            if isinstance(concept, ModelDtsObject.ModelConcept):
                text = labelPrefix + concept.label(
                    preferredLabel,
                    lang=self.lang,
                    linkroleHint=relationshipSet.linkrole)
                if (self.arcrole
                        in ("XBRL-dimensions", XbrlConst.hypercubeDimension)
                        and concept.isTypedDimension
                        and concept.typedDomainElement is not None):
                    text += " (typedDomain={0})".format(
                        concept.typedDomainElement.qname)
            elif isinstance(concept, ModelInstanceObject.ModelFact):
                if concept.concept is not None:
                    text = labelPrefix + concept.concept.label(
                        preferredLabel,
                        lang=self.lang,
                        linkroleHint=relationshipSet.linkrole)
                else:
                    text = str(concept.qname)
                if concept.contextID:
                    text += " [" + concept.contextID + "] = " + concept.effectiveValue
            elif self.arcrole == "Table-rendering":
                text = concept.localName
            elif isinstance(concept, ModelRenderingObject.ModelTable):
                text = (concept.genLabel(lang=self.lang, strip=True)
                        or concept.localName)
                isModelTable = True
            elif isinstance(concept, ModelDtsObject.ModelResource):
                if self.showReferences:
                    text = (concept.viewText() or concept.localName)
                else:
                    text = (Locale.rtlString(concept.textValue.strip(),
                                             lang=concept.xmlLang)
                            or concept.localName)
            else:  # just a resource
                text = concept.localName

            childnode = self.treeView.insert(parentnode,
                                             "end",
                                             modelObject.objectId(self.id),
                                             text=text,
                                             tags=("odd" if n
                                                   & 1 else "even", ))

            # Check if we need special rendering of this item
            for pluginXbrlMethod in pluginClassMethods(
                    "CntlrWinMain.Rendering.RenderConcept"):
                stopPlugin = pluginXbrlMethod(isModelTable, concept, text,
                                              self, self.modelXbrl, childnode)
                if stopPlugin == True:
                    break

            childRelationshipSet = relationshipSet
            if self.arcrole == XbrlConst.parentChild:  # extra columns
                if isRelation:
                    preferredLabel = modelObject.preferredLabel
                    if preferredLabel and preferredLabel.startswith(
                            "http://www.xbrl.org/2003/role/"):
                        preferredLabel = os.path.basename(preferredLabel)
                    self.treeView.set(childnode, "preferredLabel",
                                      preferredLabel)
                self.treeView.set(childnode, "type", concept.niceType)
                self.treeView.set(childnode, "references",
                                  viewReferences(concept))
            elif self.arcrole == XbrlConst.summationItem:
                if isRelation:
                    self.treeView.set(childnode, "weight",
                                      "{:+0g} ".format(modelObject.weight))
                self.treeView.set(childnode, "balance", concept.balance)
            elif self.arcrole == "XBRL-dimensions" and isRelation:  # extra columns
                relArcrole = modelObject.arcrole
                self.treeView.set(childnode, "arcrole",
                                  os.path.basename(relArcrole))
                if relArcrole in (XbrlConst.all, XbrlConst.notAll):
                    self.treeView.set(childnode, "contextElement",
                                      modelObject.contextElement)
                    self.treeView.set(childnode, "closed", modelObject.closed)
                elif relArcrole in (XbrlConst.dimensionDomain,
                                    XbrlConst.domainMember):
                    self.treeView.set(childnode, "usable", modelObject.usable)
                childRelationshipSet = self.modelXbrl.relationshipSet(
                    XbrlConst.consecutiveArcrole.get(relArcrole,
                                                     "XBRL-dimensions"),
                    modelObject.consecutiveLinkrole)
            elif self.arcrole == "Table-rendering":  # extra columns
                try:
                    header = concept.header(lang=self.lang,
                                            strip=True,
                                            evaluate=False)
                except AttributeError:
                    header = None  # could be a filter
                if isRelation and header is None:
                    header = "{0} {1}".format(
                        os.path.basename(modelObject.arcrole),
                        concept.xlinkLabel)
                self.treeView.set(childnode, "header", header)
                if concept.get("abstract") == "true":
                    self.treeView.set(childnode, "abstract",
                                      '\u2713')  # checkmark unicode character
                if concept.get("merge") == "true":
                    self.treeView.set(childnode, "merge",
                                      '\u2713')  # checkmark unicode character
                if isRelation:
                    self.treeView.set(childnode, "axis",
                                      modelObject.axisDisposition)
                    if isinstance(concept,
                                  (ModelEuAxisCoord, ModelRuleDefinitionNode)):
                        self.treeView.set(
                            childnode, "priItem",
                            concept.aspectValue(None, Aspect.CONCEPT))
                        self.treeView.set(
                            childnode, "dims", ' '.join(
                                ("{0},{1}".format(
                                    dim, concept.aspectValue(None, dim))
                                 for dim in (concept.aspectValue(
                                     None, Aspect.DIMENSIONS, inherit=False)
                                             or []))))
            elif self.isResourceArcrole:  # resource columns
                if isRelation:
                    self.treeView.set(childnode, "arcrole",
                                      os.path.basename(modelObject.arcrole))
                if isinstance(concept, ModelDtsObject.ModelResource):
                    self.treeView.set(childnode, "resource", concept.localName)
                    self.treeView.set(childnode, "resourcerole",
                                      os.path.basename(concept.role or ''))
                    self.treeView.set(childnode, "lang", concept.xmlLang)
            self.id += 1
            self.tag_has[modelObject.objectId()].append(childnode)
            if isRelation:
                self.tag_has[modelObject.toModelObject.objectId()].append(
                    childnode)
            if concept not in visited:
                visited.add(concept)
                for modelRel in childRelationshipSet.fromModelObject(concept):
                    nestedRelationshipSet = childRelationshipSet
                    targetRole = modelRel.targetRole
                    if self.arcrole == XbrlConst.summationItem:
                        childPrefix = "({:0g}) ".format(
                            modelRel.weight
                        )  # format without .0 on integer weights
                    elif targetRole is None or len(targetRole) == 0:
                        targetRole = relationshipSet.linkrole
                        childPrefix = ""
                    else:
                        nestedRelationshipSet = self.modelXbrl.relationshipSet(
                            childRelationshipSet.arcrole, targetRole)
                        childPrefix = "(via targetRole) "
                    toConcept = modelRel.toModelObject
                    if toConcept in visited:
                        childPrefix += "(loop)"
                    labelrole = modelRel.preferredLabel
                    if not labelrole or self.labelrole == conceptNameLabelRole:
                        labelrole = self.labelrole
                    n += 1  # child has opposite row style of parent
                    self.viewConcept(toConcept, modelRel, childPrefix,
                                     labelrole, childnode, n,
                                     nestedRelationshipSet, visited)
                visited.remove(concept)
        except AttributeError:
            return  # bad object, don't try to display
Exemple #53
0
def parseAndRun(args):
    """interface used by Main program and py.test (arelle_test.py)
    """
    try:
        from arelle import webserver
        hasWebServer = True
    except ImportError:
        hasWebServer = False
    cntlr = CntlrCmdLine()  # need controller for plug ins to be loaded
    usage = "usage: %prog [options]"
    
    parser = OptionParser(usage, version="Arelle(r) {0}".format(Version.version))
    parser.add_option("-f", "--file", dest="entrypointFile",
                      help=_("FILENAME is an entry point, which may be "
                             "an XBRL instance, schema, linkbase file, "
                             "inline XBRL instance, testcase file, "
                             "testcase index file.  FILENAME may be "
                             "a local file or a URI to a web located file."))
    parser.add_option("--username", dest="username",
                      help=_("user name if needed (with password) for web file retrieval"))
    parser.add_option("--password", dest="password",
                      help=_("password if needed (with user name) for web retrieval"))
    # special option for web interfaces to suppress closing an opened modelXbrl
    parser.add_option("--keepOpen", dest="keepOpen", action="store_true", help=SUPPRESS_HELP)
    parser.add_option("-i", "--import", dest="importFiles",
                      help=_("FILENAME is a list of files to import to the DTS, such as "
                             "additional formula or label linkbases.  "
                             "Multiple file names are separated by a '|' character. "))
    parser.add_option("-d", "--diff", dest="diffFile",
                      help=_("FILENAME is a second entry point when "
                             "comparing (diffing) two DTSes producing a versioning report."))
    parser.add_option("-r", "--report", dest="versReportFile",
                      help=_("FILENAME is the filename to save as the versioning report."))
    parser.add_option("-v", "--validate",
                      action="store_true", dest="validate",
                      help=_("Validate the file according to the entry "
                             "file type.  If an XBRL file, it is validated "
                             "according to XBRL validation 2.1, calculation linkbase validation "
                             "if either --calcDecimals or --calcPrecision are specified, and "
                             "SEC Edgar Filing Manual (if --efm selected) or Global Filer Manual "
                             "disclosure system validation (if --gfm=XXX selected). "
                             "If a test suite or testcase, the test case variations "
                             "are individually so validated. "
                             "If formulae are present they will be validated and run unless --formula=none is specified. "
                             ))
    parser.add_option("--calcDecimals", action="store_true", dest="calcDecimals",
                      help=_("Specify calculation linkbase validation inferring decimals."))
    parser.add_option("--calcdecimals", action="store_true", dest="calcDecimals", help=SUPPRESS_HELP)
    parser.add_option("--calcPrecision", action="store_true", dest="calcPrecision",
                      help=_("Specify calculation linkbase validation inferring precision."))
    parser.add_option("--calcprecision", action="store_true", dest="calcPrecision", help=SUPPRESS_HELP)
    parser.add_option("--efm", action="store_true", dest="validateEFM",
                      help=_("Select Edgar Filer Manual (U.S. SEC) disclosure system validation (strict)."))
    parser.add_option("--gfm", action="store", dest="disclosureSystemName", help=SUPPRESS_HELP)
    parser.add_option("--disclosureSystem", action="store", dest="disclosureSystemName",
                      help=_("Specify a disclosure system name and"
                             " select disclosure system validation.  "
                             "Enter --disclosureSystem=help for list of names or help-verbose for list of names and descriptions. "))
    parser.add_option("--disclosuresystem", action="store", dest="disclosureSystemName", help=SUPPRESS_HELP)
    parser.add_option("--hmrc", action="store_true", dest="validateHMRC",
                      help=_("Select U.K. HMRC disclosure system validation."))
    parser.add_option("--utr", action="store_true", dest="utrValidate",
                      help=_("Select validation with respect to Unit Type Registry."))
    parser.add_option("--utrUrl", action="store", dest="utrUrl",
                      help=_("Override disclosure systems Unit Type Registry location (URL or file path)."))
    parser.add_option("--utrurl", action="store", dest="utrUrl", help=SUPPRESS_HELP)
    parser.add_option("--infoset", action="store_true", dest="infosetValidate",
                      help=_("Select validation with respect testcase infosets."))
    parser.add_option("--labelLang", action="store", dest="labelLang",
                      help=_("Language for labels in following file options (override system settings)"))
    parser.add_option("--labellang", action="store", dest="labelLang", help=SUPPRESS_HELP)
    parser.add_option("--labelRole", action="store", dest="labelRole",
                      help=_("Label role for labels in following file options (instead of standard label)"))
    parser.add_option("--labelrole", action="store", dest="labelRole", help=SUPPRESS_HELP)
    parser.add_option("--DTS", "--csvDTS", action="store", dest="DTSFile",
                      help=_("Write DTS tree into FILE (may be .csv or .html)"))
    parser.add_option("--facts", "--csvFacts", action="store", dest="factsFile",
                      help=_("Write fact list into FILE"))
    parser.add_option("--factListCols", action="store", dest="factListCols",
                      help=_("Columns for fact list file"))
    parser.add_option("--factTable", "--csvFactTable", action="store", dest="factTableFile",
                      help=_("Write fact table into FILE"))
    parser.add_option("--concepts", "--csvConcepts", action="store", dest="conceptsFile",
                      help=_("Write concepts into FILE"))
    parser.add_option("--pre", "--csvPre", action="store", dest="preFile",
                      help=_("Write presentation linkbase into FILE"))
    parser.add_option("--cal", "--csvCal", action="store", dest="calFile",
                      help=_("Write calculation linkbase into FILE"))
    parser.add_option("--dim", "--csvDim", action="store", dest="dimFile",
                      help=_("Write dimensions (of definition) linkbase into FILE"))
    parser.add_option("--formulae", "--htmlFormulae", action="store", dest="formulaeFile",
                      help=_("Write formulae linkbase into FILE"))
    parser.add_option("--viewArcrole", action="store", dest="viewArcrole",
                      help=_("Write linkbase relationships for viewArcrole into viewFile"))
    parser.add_option("--viewarcrole", action="store", dest="viewArcrole", help=SUPPRESS_HELP)
    parser.add_option("--viewFile", action="store", dest="viewFile",
                      help=_("Write linkbase relationships for viewArcrole into viewFile"))
    parser.add_option("--viewfile", action="store", dest="viewFile", help=SUPPRESS_HELP)
    parser.add_option("--testReport", "--csvTestReport", action="store", dest="testReport",
                      help=_("Write test report of validation (of test cases) into FILE"))
    parser.add_option("--testreport", "--csvtestreport", action="store", dest="testReport", help=SUPPRESS_HELP)
    parser.add_option("--testReportCols", action="store", dest="testReportCols",
                      help=_("Columns for test report file"))
    parser.add_option("--testreportcols", action="store", dest="testReportCols", help=SUPPRESS_HELP)
    parser.add_option("--rssReport", action="store", dest="rssReport",
                      help=_("Write RSS report into FILE"))
    parser.add_option("--rssreport", action="store", dest="rssReport", help=SUPPRESS_HELP)
    parser.add_option("--rssReportCols", action="store", dest="rssReportCols",
                      help=_("Columns for RSS report file"))
    parser.add_option("--rssreportcols", action="store", dest="rssReportCols", help=SUPPRESS_HELP)
    parser.add_option("--logFile", action="store", dest="logFile",
                      help=_("Write log messages into file, otherwise they go to standard output.  " 
                             "If file ends in .xml it is xml-formatted, otherwise it is text. "))
    parser.add_option("--logfile", action="store", dest="logFile", help=SUPPRESS_HELP)
    parser.add_option("--logFormat", action="store", dest="logFormat",
                      help=_("Logging format for messages capture, otherwise default is \"[%(messageCode)s] %(message)s - %(file)s\"."))
    parser.add_option("--logformat", action="store", dest="logFormat", help=SUPPRESS_HELP)
    parser.add_option("--logLevel", action="store", dest="logLevel",
                      help=_("Minimum level for messages capture, otherwise the message is ignored.  " 
                             "Current order of levels are debug, info, info-semantic, warning, warning-semantic, warning, assertion-satisfied, inconsistency, error-semantic, assertion-not-satisfied, and error. "))
    parser.add_option("--loglevel", action="store", dest="logLevel", help=SUPPRESS_HELP)
    parser.add_option("--logLevelFilter", action="store", dest="logLevelFilter",
                      help=_("Regular expression filter for logLevel.  " 
                             "(E.g., to not match *-semantic levels, logLevelFilter=(?!^.*-semantic$)(.+). "))
    parser.add_option("--loglevelfilter", action="store", dest="logLevelFilter", help=SUPPRESS_HELP)
    parser.add_option("--logCodeFilter", action="store", dest="logCodeFilter",
                      help=_("Regular expression filter for log message code."))
    parser.add_option("--logcodefilter", action="store", dest="logCodeFilter", help=SUPPRESS_HELP)
    parser.add_option("--showOptions", action="store_true", dest="showOptions", help=SUPPRESS_HELP)
    parser.add_option("--parameters", action="store", dest="parameters", help=_("Specify parameters for formula and validation (name=value[,name=value])."))
    parser.add_option("--parameterSeparator", action="store", dest="parameterSeparator", help=_("Specify parameters separator string (if other than comma)."))
    parser.add_option("--parameterseparator", action="store", dest="parameterSeparator", help=SUPPRESS_HELP)
    parser.add_option("--formula", choices=("validate", "run", "none"), dest="formulaAction", 
                      help=_("Specify formula action: "
                             "validate - validate only, without running, "
                             "run - validate and run, or "
                             "none - prevent formula validation or running when also specifying -v or --validate.  "
                             "if this option is not specified, -v or --validate will validate and run formulas if present"))
    parser.add_option("--formulaParamExprResult", action="store_true", dest="formulaParamExprResult", help=_("Specify formula tracing."))
    parser.add_option("--formulaParamInputValue", action="store_true", dest="formulaParamInputValue", help=_("Specify formula tracing."))
    parser.add_option("--formulaCallExprSource", action="store_true", dest="formulaCallExprSource", help=_("Specify formula tracing."))
    parser.add_option("--formulaCallExprCode", action="store_true", dest="formulaCallExprCode", help=_("Specify formula tracing."))
    parser.add_option("--formulaCallExprEval", action="store_true", dest="formulaCallExprEval", help=_("Specify formula tracing."))
    parser.add_option("--formulaCallExprResult", action="store_true", dest="formulaCallExprResult", help=_("Specify formula tracing."))
    parser.add_option("--formulaVarSetExprEval", action="store_true", dest="formulaVarSetExprEval", help=_("Specify formula tracing."))
    parser.add_option("--formulaVarSetExprResult", action="store_true", dest="formulaVarSetExprResult", help=_("Specify formula tracing."))
    parser.add_option("--formulaVarSetTiming", action="store_true", dest="timeVariableSetEvaluation", help=_("Specify showing times of variable set evaluation."))
    parser.add_option("--formulaAsserResultCounts", action="store_true", dest="formulaAsserResultCounts", help=_("Specify formula tracing."))
    parser.add_option("--formulaFormulaRules", action="store_true", dest="formulaFormulaRules", help=_("Specify formula tracing."))
    parser.add_option("--formulaVarsOrder", action="store_true", dest="formulaVarsOrder", help=_("Specify formula tracing."))
    parser.add_option("--formulaVarExpressionSource", action="store_true", dest="formulaVarExpressionSource", help=_("Specify formula tracing."))
    parser.add_option("--formulaVarExpressionCode", action="store_true", dest="formulaVarExpressionCode", help=_("Specify formula tracing."))
    parser.add_option("--formulaVarExpressionEvaluation", action="store_true", dest="formulaVarExpressionEvaluation", help=_("Specify formula tracing."))
    parser.add_option("--formulaVarExpressionResult", action="store_true", dest="formulaVarExpressionResult", help=_("Specify formula tracing."))
    parser.add_option("--formulaVarFilterWinnowing", action="store_true", dest="formulaVarFilterWinnowing", help=_("Specify formula tracing."))
    parser.add_option("--formulaVarFiltersResult", action="store_true", dest="formulaVarFiltersResult", help=_("Specify formula tracing."))
    parser.add_option("--uiLang", action="store", dest="uiLang",
                      help=_("Language for user interface (override system settings, such as program messages).  Does not save setting."))
    parser.add_option("--uilang", action="store", dest="uiLang", help=SUPPRESS_HELP)
    parser.add_option("--proxy", action="store", dest="proxy",
                      help=_("Modify and re-save proxy settings configuration.  " 
                             "Enter 'system' to use system proxy setting, 'none' to use no proxy, "
                             "'http://[user[:password]@]host[:port]' "
                             " (e.g., http://192.168.1.253, http://example.com:8080, http://joe:[email protected]:8080), "
                             " or 'show' to show current setting, ." ))
    parser.add_option("--internetConnectivity", choices=("online", "offline"), dest="internetConnectivity", 
                      help=_("Specify internet connectivity: online or offline"))
    parser.add_option("--internetconnectivity", action="store", dest="internetConnectivity", help=SUPPRESS_HELP)
    parser.add_option("--internetTimeout", type="int", dest="internetTimeout", 
                      help=_("Specify internet connection timeout in seconds (0 means unlimited)."))
    parser.add_option("--internettimeout", type="int", action="store", dest="internetTimeout", help=SUPPRESS_HELP)
    parser.add_option("--xdgConfigHome", action="store", dest="xdgConfigHome", 
                      help=_("Specify non-standard location for configuration and cache files (overrides environment parameter XDG_CONFIG_HOME)."))
    parser.add_option("--plugins", action="store", dest="plugins",
                      help=_("Modify plug-in configuration.  "
                             "Re-save unless 'temp' is in the module list.  " 
                             "Enter 'show' to show current plug-in configuration.  "
                             "Commands show, and module urls are '|' separated: "
                             "+url to add plug-in by its url or filename, ~name to reload a plug-in by its name, -name to remove a plug-in by its name, "
                             "relative URLs are relative to installation plug-in directory, "
                             " (e.g., '+http://arelle.org/files/hello_web.py', '+C:\Program Files\Arelle\examples\plugin\hello_dolly.py' to load, "
                             "or +../examples/plugin/hello_dolly.py for relative use of examples directory, "
                             "~Hello Dolly to reload, -Hello Dolly to remove).  "
                             "If + is omitted from .py file nothing is saved (same as temp).  "
                             "Packaged plug-in urls are their directory's url.  " ))
    parser.add_option("--abortOnMajorError", action="store_true", dest="abortOnMajorError", help=_("Abort process on major error, such as when load is unable to find an entry or discovered file."))
    parser.add_option("--collectProfileStats", action="store_true", dest="collectProfileStats", help=_("Collect profile statistics, such as timing of validation activities and formulae."))
    if hasWebServer:
        parser.add_option("--webserver", action="store", dest="webserver",
                          help=_("start web server on host:port[:server] for REST and web access, e.g., --webserver locahost:8080, "
                                 "or specify nondefault a server name, such as cherrypy, --webserver locahost:8080:cherrypy. "
                                 "(It is possible to specify options to be defaults for the web server, such as disclosureSystem and validations, but not including file names.) "))
    pluginOptionsIndex = len(parser.option_list)
    for optionsExtender in pluginClassMethods("CntlrCmdLine.Options"):
        optionsExtender(parser)
    pluginLastOptionIndex = len(parser.option_list)
    parser.add_option("-a", "--about",
                      action="store_true", dest="about",
                      help=_("Show product version, copyright, and license."))
    
    if args is None and cntlr.isGAE:
        args = ["--webserver=::gae"]
    elif cntlr.isMSW:
        # if called from java on Windows any empty-string arguments are lost, see:
        # http://bugs.sun.com/view_bug.do?bug_id=6518827
        # insert needed arguments
        args = []
        namedOptions = set()
        optionsWithArg = set()
        for option in parser.option_list:
            names = str(option).split('/')
            namedOptions.update(names)
            if option.action == "store":
                optionsWithArg.update(names)
        priorArg = None
        for arg in sys.argv[1:]:
            if priorArg in optionsWithArg and arg in namedOptions:
                # probable java/MSFT interface bug 6518827
                args.append('')  # add empty string argument
            args.append(arg)
            priorArg = arg
        
    (options, leftoverArgs) = parser.parse_args(args)
    if options.about:
        print(_("\narelle(r) {0}\n\n"
                "An open source XBRL platform\n"
                "(c) 2010-2013 Mark V Systems Limited\n"
                "All rights reserved\nhttp://www.arelle.org\[email protected]\n\n"
                "Licensed under the Apache License, Version 2.0 (the \"License\"); "
                "you may not \nuse this file except in compliance with the License.  "
                "You may obtain a copy \nof the License at "
                "'http://www.apache.org/licenses/LICENSE-2.0'\n\n"
                "Unless required by applicable law or agreed to in writing, software \n"
                "distributed under the License is distributed on an \"AS IS\" BASIS, \n"
                "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  \n"
                "See the License for the specific language governing permissions and \n"
                "limitations under the License."
                "\n\nIncludes:"
                "\n   Python(r) (c) 2001-2013 Python Software Foundation"
                "\n   PyParsing (c) 2003-2013 Paul T. McGuire"
                "\n   lxml (c) 2004 Infrae, ElementTree (c) 1999-2004 by Fredrik Lundh"
                "\n   xlrd (c) 2005-2009 Stephen J. Machin, Lingfo Pty Ltd, (c) 2001 D. Giffin, (c) 2000 A. Khan"
                "\n   xlwt (c) 2007 Stephen J. Machin, Lingfo Pty Ltd, (c) 2005 R. V. Kiseliov"
                "{1}"
                ).format(Version.version,
                         _("\n   Bottle (c) 2011-2013 Marcel Hellkamp") if hasWebServer else ""))
    elif options.disclosureSystemName in ("help", "help-verbose"):
        text = _("Disclosure system choices: \n{0}").format(' \n'.join(cntlr.modelManager.disclosureSystem.dirlist(options.disclosureSystemName)))
        try:
            print(text)
        except UnicodeEncodeError:
            print(text.encode("ascii", "replace").decode("ascii"))
    elif len(leftoverArgs) != 0 or (options.entrypointFile is None and 
                                    ((not options.proxy) and (not options.plugins) and
                                     (not any(pluginOption for pluginOption in parser.option_list[pluginOptionsIndex:pluginLastOptionIndex])) and
                                     (not hasWebServer or options.webserver is None))):
        parser.error(_("incorrect arguments, please try\n  python CntlrCmdLine.py --help"))
    elif hasWebServer and options.webserver:
        # webserver incompatible with file operations
        if any((options.entrypointFile, options.importFiles, options.diffFile, options.versReportFile,
                options.factsFile, options.factListCols, options.factTableFile,
                options.conceptsFile, options.preFile, options.calFile, options.dimFile, options.formulaeFile, options.viewArcrole, options.viewFile,
                )):
            parser.error(_("incorrect arguments with --webserver, please try\n  python CntlrCmdLine.py --help"))
        else:
            cntlr.startLogging(logFileName='logToBuffer')
            from arelle import CntlrWebMain
            CntlrWebMain.startWebserver(cntlr, options)
    else:
        # parse and run the FILENAME
        cntlr.startLogging(logFileName=(options.logFile or "logToPrint"),
                           logFormat=(options.logFormat or "[%(messageCode)s] %(message)s - %(file)s"),
                           logLevel=(options.logLevel or "DEBUG"))
        cntlr.run(options)
        
        return cntlr
Exemple #54
0
 def file(self,
          filepath,
          binary=False,
          stripDeclaration=False,
          encoding=None):
     ''' 
         for text, return a tuple of (open file handle, encoding)
         for binary, return a tuple of (open file handle, )
     '''
     archiveFileSource = self.fileSourceContainingFilepath(filepath)
     if archiveFileSource is not None:
         if filepath.startswith(archiveFileSource.basefile):
             archiveFileName = filepath[len(archiveFileSource.basefile) +
                                        1:]
         else:  # filepath.startswith(self.baseurl)
             archiveFileName = filepath[len(archiveFileSource.baseurl) + 1:]
         if archiveFileSource.isZip:
             try:
                 if archiveFileSource.isZipBackslashed:
                     f = archiveFileName.replace("/", "\\")
                 else:
                     f = archiveFileName.replace("\\", "/")
                 b = archiveFileSource.fs.read(f)
                 if binary:
                     return (io.BytesIO(b), )
                 if encoding is None:
                     encoding = XmlUtil.encoding(b)
                 if stripDeclaration:
                     b = stripDeclarationBytes(b)
                 return (FileNamedTextIOWrapper(filepath,
                                                io.BytesIO(b),
                                                encoding=encoding),
                         encoding)
             except KeyError:
                 raise ArchiveFileIOError(self, errno.ENOENT,
                                          archiveFileName)
         elif archiveFileSource.isTarGz:
             try:
                 fh = archiveFileSource.fs.extractfile(archiveFileName)
                 b = fh.read()
                 fh.close(
                 )  # doesn't seem to close properly using a with construct
                 if binary:
                     return (io.BytesIO(b), )
                 if encoding is None:
                     encoding = XmlUtil.encoding(b)
                 if stripDeclaration:
                     b = stripDeclarationBytes(b)
                 return (FileNamedTextIOWrapper(filepath,
                                                io.BytesIO(b),
                                                encoding=encoding),
                         encoding)
             except KeyError:
                 raise ArchiveFileIOError(self, archiveFileName)
         elif archiveFileSource.isEis:
             for docElt in self.eisDocument.iter(
                     tag="{http://www.sec.gov/edgar/common}document"):
                 outfn = docElt.findtext(
                     "{http://www.sec.gov/edgar/common}conformedName")
                 if outfn == archiveFileName:
                     b64data = docElt.findtext(
                         "{http://www.sec.gov/edgar/common}contents")
                     if b64data:
                         b = base64.b64decode(b64data.encode("latin-1"))
                         # remove BOM codes if present
                         if len(b) > 3 and b[0] == 239 and b[
                                 1] == 187 and b[2] == 191:
                             start = 3
                             length = len(b) - 3
                             b = b[start:start + length]
                         else:
                             start = 0
                             length = len(b)
                         if binary:
                             return (io.BytesIO(b), )
                         if encoding is None:
                             encoding = XmlUtil.encoding(b,
                                                         default="latin-1")
                         return (io.TextIOWrapper(io.BytesIO(b),
                                                  encoding=encoding),
                                 encoding)
             raise ArchiveFileIOError(self, errno.ENOENT, archiveFileName)
         elif archiveFileSource.isXfd:
             for data in archiveFileSource.xfdDocument.iter(tag="data"):
                 outfn = data.findtext("filename")
                 if outfn == archiveFileName:
                     b64data = data.findtext("mimedata")
                     if b64data:
                         b = base64.b64decode(b64data.encode("latin-1"))
                         # remove BOM codes if present
                         if len(b) > 3 and b[0] == 239 and b[
                                 1] == 187 and b[2] == 191:
                             start = 3
                             length = len(b) - 3
                             b = b[start:start + length]
                         else:
                             start = 0
                             length = len(b)
                         if binary:
                             return (io.BytesIO(b), )
                         if encoding is None:
                             encoding = XmlUtil.encoding(b,
                                                         default="latin-1")
                         return (io.TextIOWrapper(io.BytesIO(b),
                                                  encoding=encoding),
                                 encoding)
             raise ArchiveFileIOError(self, errno.ENOENT, archiveFileName)
         elif archiveFileSource.isInstalledTaxonomyPackage:
             # remove TAXONOMY_PACKAGE_FILE_NAME from file path
             if filepath.startswith(archiveFileSource.basefile):
                 l = len(archiveFileSource.basefile)
                 for f in TAXONOMY_PACKAGE_FILE_NAMES:
                     if filepath[l - len(f):l] == f:
                         filepath = filepath[0:l - len(f) -
                                             1] + filepath[l:]
                         break
     for pluginMethod in pluginClassMethods(
             "FileSource.File"):  #custom overrides for decription, etc
         fileResult = pluginMethod(self.cntlr, filepath, binary,
                                   stripDeclaration)
         if fileResult is not None:
             return fileResult
     if binary:
         return (openFileStream(self.cntlr, filepath, 'rb'), )
     else:
         return openXmlFileStream(self.cntlr, filepath, stripDeclaration)
Exemple #55
0
def startWebserver(_cntlr, options):
    """Called once from main program in CmtlrCmdLine to initiate web server on specified local port.
    To test WebServer run from source in IIS, use an entry like this: c:\python33\python.exe c:\\users\\myname\\mySourceFolder\\arelleCmdLine.py %s
       
    :param options: OptionParser options from parse_args of main argv arguments (the argument *webserver* provides hostname and port), port being used to startup the webserver on localhost.
    :type options: optparse.Values
    """
    global imagesDir, cntlr, optionsPrototype
    cntlr = _cntlr
    imagesDir = cntlr.imagesDir
    optionValuesTypes = _STR_NUM_TYPES + (type(None),)
    optionsPrototype = dict((option,value if isinstance(value,_STR_NUM_TYPES) else None)
                            for option in dir(options)
                            for value in (getattr(options, option),)
                            if isinstance(value,optionValuesTypes) and not option.startswith('_'))
    host, sep, portServer = options.webserver.partition(":")
    port, sep, server = portServer.partition(":")
    # start a Bottle application
    app = Bottle()

    # install REST API interfaces
    # if necessary to support CGI hosted servers below root, add <prefix:path> as first part of routes
    # and corresponding arguments to the handler methods
    
    # allow plugins to replace or add to default REST API "routes"
    pluginResult = None
    for pluginMethod in pluginClassMethods("CntlrWebMain.StartWebServer"):
        # returns a string containing "skip-routes" to block default routes and/or "skip-run" to block default app startup
        pluginResult = pluginMethod(app, cntlr, host, port, server)
        break # only provide for a single plugin of this class
    if not (isinstance(pluginResult, str) and "skip-routes" in pluginResult):
        app.route('/rest/login', GET, login_form)
        app.route('/rest/login', POST, login_submit)
        app.route('/rest/logout', GET, logout)
        app.route('/favicon.ico', GET, arelleIcon)
        app.route('/rest/xbrl/<file:path>/open', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/close', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/validation/xbrl', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/DTS', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/concepts', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/pre', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/table', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/cal', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/dim', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/facts', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/factTable', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/roleTypes', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/arcroleTypes', GETorPOST, validation)
        app.route('/rest/xbrl/<file:path>/formulae', GETorPOST, validation)
        app.route('/rest/xbrl/validation', GETorPOST, validation)
        app.route('/rest/xbrl/view', GETorPOST, validation)
        app.route('/rest/xbrl/open', GETorPOST, validation)
        app.route('/rest/xbrl/close', GETorPOST, validation)
        app.route('/images/<imgFile>', GET, image)
        app.route('/rest/xbrl/diff', GET, diff)
        app.route('/rest/configure', GET, configure)
        app.route('/rest/stopWebServer', GET, stopWebServer)
        app.route('/quickbooks/server.asmx', POST, quickbooksServer)
        app.route('/rest/quickbooks/<qbReport>/xbrl-gl/<file:path>', GET, quickbooksGLrequest)
        app.route('/rest/quickbooks/<qbReport>/xbrl-gl/<file:path>/view', GET, quickbooksGLrequest)
        app.route('/rest/quickbooks/<qbReport>/xbrl-gl/view', GET, quickbooksGLrequest)
        app.route('/rest/quickbooks/response', GET, quickbooksGLresponse)
        app.route('/quickbooks/server.html', GET, quickbooksWebPage)
        app.route('/quickbooks/localhost.crt', GET, localhostCertificate)
        app.route('/localhost.crt', GET, localhostCertificate)
        app.route('/rest/test/test', GETorPOST, testTest)
        app.route('/help', GET, helpREST)
        app.route('/about', GET, about)
        app.route('/', GET, indexPageREST)
        if server == "cgi":
            # catch a non-REST interface by cgi Interface (may be a cgi app exe module, etc)
            app.route('<cgiAppPath:path>', GETorPOST, cgiInterface)
    if not (isinstance(pluginResult, str) and "skip-run" in pluginResult):
        if server == "wsgi":
            return app
        elif server == "cgi":
            if sys.stdin is None:
                sys.stdin = open(os.devnull, 'r')
            app.run(server=server)
            sys.exit(0)
        elif server:
            sys.path.insert(0,os.path.join(os.path.dirname(__file__),"webserver"))
            app.run(host=host, port=port or 80, server=server)
        else:
            app.run(host=host, port=port or 80)
Exemple #56
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 #57
0
 def clear(self):
     self.selection = None
     self.standardTaxonomiesDict = {}
     self.familyHrefs = {}
     self.standardLocalHrefs = set()
     self.standardAuthorities = set()
     self.baseTaxonomyNamespaces = set()
     self.standardPrefixes = {}
     self.names = []
     self.name = None
     self.validationType = None
     self.exclusiveTypesPattern = None # regex of type matches exclusive with validationType
     # previously built-in types (intent to replace with plugin defined types)
     self.EFM = False
     self.GFM = False
     self.EFMorGFM = False
     self.HMRC = False
     self.SBRNL = False
     self.pluginTypes = set()
     for pluginXbrlMethod in pluginClassMethods("DisclosureSystem.Types"):
         for typeName, typeTestVariable in pluginXbrlMethod(self):
             setattr(self, typeTestVariable, False)
             self.pluginTypes.add(typeName)
     self.validateFileText = False
     self.validateEntryText = False
     self.allowedExternalHrefPattern = None
     self.allowedImageTypes = None
     self.schemaValidateSchema = None
     self.blockDisallowedReferences = False
     self.maxSubmissionSubdirectoryEntryNesting = 0
     self.defaultXmlLang = None
     self.defaultXmlEncoding = "utf-8"
     self.xmlLangPattern = None
     self.xmlLangIsInheritable = True # for label and footnote, spec sections 4.11.1.2.1 and 5.2.2.2.1
     self.defaultLanguage = None
     self.language = None
     self.standardTaxonomiesUrl = None
     self.mappingsUrl = os.path.join(self.modelManager.cntlr.configDir, "mappings.xml")
     self.mappedFiles = {}
     self.mappedPaths = []
     self.utrUrl = ["http://www.xbrl.org/utr/utr.xml"]
     self.utrStatusFilters = None
     self.utrTypeEntries = None
     self.identifierSchemePattern = None
     self.identifierValuePattern = None
     self.identifierValueName = None
     self.contextElement = None
     self.roleDefinitionPattern = None
     self.labelCheckPattern = None
     self.labelTrimPattern = None
     self.deiNamespacePattern = None
     self.deiAmendmentFlagElement = None
     self.deiCurrentFiscalYearEndDateElement = None
     self.deiDocumentFiscalYearFocusElement = None
     self.deiDocumentPeriodEndDateElement = None
     self.deiFilerIdentifierElement = None
     self.deiFilerNameElement = None
     self.logLevelFilter = None
     self.logCodeFilter = None
     self.standardTaxonomyDatabase = None
     self.standardTaxonomyUrlPattern = None
     self.options = None
     self.version = (0,0,0)
Exemple #58
0
 def loadCustomTransforms(self):
     if self.customTransforms is None:
         self.customTransforms = {}
         for pluginMethod in pluginClassMethods("ModelManager.LoadCustomTransforms"):
             pluginMethod(self.customTransforms)
Exemple #59
0
def parentMenuCommand(cntl):
    for i in range(1,100):
        for pluginMethod in pluginClassMethods("Import.Unpackaged.Entry{}".format(i)):
            pluginMethod()
Exemple #60
0
 def validateRssFeed(self):
     self.modelXbrl.info("info", "RSS Feed", modelDocument=self.modelXbrl)
     from arelle.FileSource import openFileSource
     reloadCache = getattr(self.modelXbrl, "reloadCache", False)
     for rssItem in self.modelXbrl.modelDocument.rssItems:
         if getattr(rssItem, "skipRssItem", False):
             self.modelXbrl.info(
                 "info",
                 _("skipping RSS Item %(accessionNumber)s %(formType)s %(companyName)s %(period)s"
                   ),
                 modelObject=rssItem,
                 accessionNumber=rssItem.accessionNumber,
                 formType=rssItem.formType,
                 companyName=rssItem.companyName,
                 period=rssItem.period)
             continue
         self.modelXbrl.info(
             "info",
             _("RSS Item %(accessionNumber)s %(formType)s %(companyName)s %(period)s"
               ),
             modelObject=rssItem,
             accessionNumber=rssItem.accessionNumber,
             formType=rssItem.formType,
             companyName=rssItem.companyName,
             period=rssItem.period)
         modelXbrl = None
         try:
             modelXbrl = ModelXbrl.load(
                 self.modelXbrl.modelManager,
                 openFileSource(rssItem.zippedUrl,
                                self.modelXbrl.modelManager.cntlr,
                                reloadCache=reloadCache),
                 _("validating"),
                 rssItem=rssItem)
             for pluginXbrlMethod in pluginClassMethods(
                     "RssItem.Xbrl.Loaded"):
                 pluginXbrlMethod(modelXbrl, {}, rssItem)
             if getattr(rssItem, "doNotProcessRSSitem",
                        False) or modelXbrl.modelDocument is None:
                 modelXbrl.close()
                 continue  # skip entry based on processing criteria
             self.instValidator.validate(
                 modelXbrl,
                 self.modelXbrl.modelManager.formulaOptions.typedParameters(
                 ))
             self.instValidator.close()
             rssItem.setResults(modelXbrl)
             self.modelXbrl.modelManager.viewModelObject(
                 self.modelXbrl, rssItem.objectId())
             for pluginXbrlMethod in pluginClassMethods("Validate.RssItem"):
                 pluginXbrlMethod(self, modelXbrl, rssItem)
             modelXbrl.close()
         except Exception as err:
             self.modelXbrl.error(
                 "exception:" + type(err).__name__,
                 _("RSS item validation exception: %(error)s, instance: %(instance)s"
                   ),
                 modelXbrl=(self.modelXbrl, modelXbrl),
                 instance=rssItem.zippedUrl,
                 error=err,
                 exc_info=True)
             try:
                 self.instValidator.close()
                 if modelXbrl is not None:
                     modelXbrl.close()
             except Exception as err:
                 pass
         del modelXbrl  # completely dereference