arelle-release 2.36.30__py3-none-any.whl → 2.36.32__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arelle-release might be problematic. Click here for more details.
- arelle/CntlrCmdLine.py +90 -52
- arelle/CntlrWinMain.py +29 -2
- arelle/ModelManager.py +2 -0
- arelle/ModelValue.py +5 -4
- arelle/RuntimeOptions.py +1 -0
- arelle/ValidateXbrlDTS.py +83 -27
- arelle/ViewFileRelationshipSet.py +4 -2
- arelle/ViewFileRenderedGrid.py +1 -1
- arelle/ViewFileRenderedLayout.py +0 -1
- arelle/ViewWinRelationshipSet.py +4 -3
- arelle/ViewWinRenderedGrid.py +1 -1
- arelle/XmlUtil.py +1 -1
- arelle/_version.py +2 -2
- arelle/formula/XPathParser.py +1 -1
- arelle/plugin/saveLoadableOIM.py +38 -5
- arelle/rendering/RenderingLayout.py +1 -1
- arelle/rendering/RenderingResolution.py +2 -2
- {arelle_release-2.36.30.dist-info → arelle_release-2.36.32.dist-info}/METADATA +3 -2
- {arelle_release-2.36.30.dist-info → arelle_release-2.36.32.dist-info}/RECORD +45 -45
- {arelle_release-2.36.30.dist-info → arelle_release-2.36.32.dist-info}/WHEEL +1 -1
- tests/integration_tests/ui_tests/ArelleGUITest/ArelleGUITest/ArelleGUITest.csproj +2 -2
- tests/integration_tests/validation/conformance_suite_configurations/cipc_current.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/dba_current.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/dba_multi_current.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2021.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2022.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2023.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2024.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2021.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2022.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2023.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2024.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/hmrc_current.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/kvk_nt16.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/kvk_nt17.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/kvk_nt18.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/kvk_nt19.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/nl_nt16.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/nl_nt17.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/nl_nt18.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/nl_nt19.py +1 -0
- tests/integration_tests/validation/conformance_suite_configurations/ros_current.py +1 -0
- {arelle_release-2.36.30.dist-info → arelle_release-2.36.32.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.36.30.dist-info → arelle_release-2.36.32.dist-info/licenses}/LICENSE.md +0 -0
- {arelle_release-2.36.30.dist-info → arelle_release-2.36.32.dist-info}/top_level.txt +0 -0
arelle/CntlrCmdLine.py
CHANGED
|
@@ -6,33 +6,59 @@ This module is Arelle's controller in command line non-interactive mode
|
|
|
6
6
|
See COPYRIGHT.md for copyright information.
|
|
7
7
|
'''
|
|
8
8
|
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import
|
|
11
|
-
|
|
9
|
+
|
|
10
|
+
import datetime
|
|
11
|
+
import fnmatch
|
|
12
|
+
import gettext
|
|
13
|
+
import glob
|
|
14
|
+
import json
|
|
15
|
+
import logging
|
|
16
|
+
import os
|
|
17
|
+
import platform
|
|
18
|
+
import shlex
|
|
19
|
+
import sys
|
|
20
|
+
import threading
|
|
21
|
+
import time
|
|
22
|
+
import traceback
|
|
23
|
+
from optparse import SUPPRESS_HELP, Option, OptionGroup, OptionParser
|
|
24
|
+
from pprint import pprint
|
|
25
|
+
|
|
12
26
|
import regex as re
|
|
13
|
-
from
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
27
|
+
from lxml import etree
|
|
28
|
+
|
|
29
|
+
from arelle import (
|
|
30
|
+
Cntlr,
|
|
31
|
+
FileSource,
|
|
32
|
+
ModelDocument,
|
|
33
|
+
PackageManager,
|
|
34
|
+
PluginManager,
|
|
35
|
+
ValidateDuplicateFacts,
|
|
36
|
+
Version,
|
|
37
|
+
ViewFileConcepts,
|
|
38
|
+
ViewFileDTS,
|
|
39
|
+
ViewFileFactList,
|
|
40
|
+
ViewFileFactTable,
|
|
41
|
+
ViewFileFormulae,
|
|
42
|
+
ViewFileRelationshipSet,
|
|
43
|
+
ViewFileRoleTypes,
|
|
44
|
+
ViewFileRssFeed,
|
|
45
|
+
ViewFileTests,
|
|
46
|
+
XbrlConst,
|
|
47
|
+
XmlUtil,
|
|
48
|
+
)
|
|
20
49
|
from arelle.BetaFeatures import BETA_FEATURES_AND_DESCRIPTIONS
|
|
21
|
-
from arelle.ModelValue import qname
|
|
22
50
|
from arelle.Locale import format_string, setApplicationLocale, setDisableRTL
|
|
23
51
|
from arelle.ModelFormulaObject import FormulaOptions
|
|
24
|
-
from arelle import
|
|
25
|
-
from arelle.
|
|
52
|
+
from arelle.ModelValue import qname
|
|
53
|
+
from arelle.oim.xml.Save import saveOimReportToXmlInstance
|
|
54
|
+
from arelle.rendering import RenderingEvaluator
|
|
55
|
+
from arelle.RuntimeOptions import RuntimeOptions, RuntimeOptionsException
|
|
26
56
|
from arelle.SocketUtils import INTERNET_CONNECTIVITY, OFFLINE
|
|
57
|
+
from arelle.SystemInfo import PlatformOS, getSystemInfo, getSystemWordSize, hasWebServer, isCGI, isGAE
|
|
27
58
|
from arelle.typing import TypeGetText
|
|
28
59
|
from arelle.UrlUtil import isHttpUrl
|
|
29
|
-
from arelle.
|
|
60
|
+
from arelle.ValidateXbrlDTS import ValidateBaseTaxonomiesMode
|
|
30
61
|
from arelle.WebCache import proxyTuple
|
|
31
|
-
from arelle.SystemInfo import getSystemInfo, getSystemWordSize, hasWebServer, isCGI, isGAE, PlatformOS
|
|
32
|
-
from pprint import pprint
|
|
33
|
-
import logging
|
|
34
|
-
from lxml import etree
|
|
35
|
-
import glob
|
|
36
62
|
|
|
37
63
|
win32file = win32api = win32process = pywintypes = None
|
|
38
64
|
STILL_ACTIVE = 259 # MS Windows process status constants
|
|
@@ -51,10 +77,7 @@ def main():
|
|
|
51
77
|
:type message: [str]
|
|
52
78
|
"""
|
|
53
79
|
envArgs = os.getenv("ARELLE_ARGS")
|
|
54
|
-
if envArgs:
|
|
55
|
-
args = shlex.split(envArgs)
|
|
56
|
-
else:
|
|
57
|
-
args = sys.argv[1:]
|
|
80
|
+
args = shlex.split(envArgs) if envArgs else sys.argv[1:]
|
|
58
81
|
setApplicationLocale()
|
|
59
82
|
gettext.install("arelle")
|
|
60
83
|
parseAndRun(args)
|
|
@@ -96,7 +119,7 @@ def parseArgs(args):
|
|
|
96
119
|
cntlr = CntlrCmdLine(uiLang=uiLang, disable_persistent_config=disable_persistent_config) # This Cntlr is needed for translations and to enable the web cache. The cntlr is not used outside the parse function
|
|
97
120
|
usage = "usage: %prog [options]"
|
|
98
121
|
parser = OptionParser(usage,
|
|
99
|
-
version="Arelle(r) {
|
|
122
|
+
version=f"Arelle(r) {Version.__version__} ({getSystemWordSize()}bit)",
|
|
100
123
|
conflict_handler="resolve") # allow reloading plug-in options without errors
|
|
101
124
|
parser.add_option("-f", "--file", dest="entrypointFile",
|
|
102
125
|
help=_("FILENAME is an entry point, which may be "
|
|
@@ -137,6 +160,15 @@ def parseArgs(args):
|
|
|
137
160
|
choices=[a.value for a in ValidateDuplicateFacts.DUPLICATE_TYPE_ARG_MAP],
|
|
138
161
|
dest="validateDuplicateFacts",
|
|
139
162
|
help=_("Select which types of duplicates should trigger warnings."))
|
|
163
|
+
parser.add_option("--baseTaxonomyValidation", "--basetaxonomyvalidation",
|
|
164
|
+
choices=("disclosureSystem", "none", "all"),
|
|
165
|
+
dest="baseTaxonomyValidationMode",
|
|
166
|
+
default="disclosureSystem",
|
|
167
|
+
help=_("""Specify if base taxonomies should be validated.
|
|
168
|
+
Skipping validation of base taxonomy files which are known to be valid can significantly reduce validation time.
|
|
169
|
+
disclosureSystem - (default) skip validation of base taxonomy files which are known to be valid by the disclosure system
|
|
170
|
+
none - skip validation of all base taxonomies
|
|
171
|
+
all - validate all base taxonomies"""))
|
|
140
172
|
parser.add_option("--saveOIMToXMLReport", "--saveoimtoxmlreport", "--saveOIMinstance", "--saveoiminstance",
|
|
141
173
|
action="store",
|
|
142
174
|
dest="saveOIMToXMLReport",
|
|
@@ -397,7 +429,7 @@ def parseArgs(args):
|
|
|
397
429
|
PluginManager.reset()
|
|
398
430
|
break
|
|
399
431
|
# add plug-in options
|
|
400
|
-
for optionsExtender in pluginClassMethods("CntlrCmdLine.Options"):
|
|
432
|
+
for optionsExtender in PluginManager.pluginClassMethods("CntlrCmdLine.Options"):
|
|
401
433
|
optionsExtender(parser)
|
|
402
434
|
pluginLastOptionIndex = len(parser.option_list)
|
|
403
435
|
pluginLastOptionsGroupIndex = len(parser.option_groups)
|
|
@@ -459,7 +491,7 @@ def parseArgs(args):
|
|
|
459
491
|
version=Version.__version__,
|
|
460
492
|
wordSize=getSystemWordSize(),
|
|
461
493
|
platform=platform.machine(),
|
|
462
|
-
copyrightLabel=copyrightLabel,
|
|
494
|
+
copyrightLabel=Version.copyrightLabel,
|
|
463
495
|
pythonVersion=f'{sys.version_info[0]}.{sys.version_info[1]}.{sys.version_info[2]}',
|
|
464
496
|
lxmlVersion=f'{etree.LXML_VERSION[0]}.{etree.LXML_VERSION[1]}.{etree.LXML_VERSION[2]}',
|
|
465
497
|
bottleCopyright="\n Bottle (c) 2011-2013 Marcel Hellkamp" if hasWebServer() else ""
|
|
@@ -568,7 +600,7 @@ def filesourceEntrypointFiles(filesource, entrypointFiles=None, inlineOnly=False
|
|
|
568
600
|
if report.isInline:
|
|
569
601
|
reportEntries = [{"file": f} for f in report.fullPathFiles]
|
|
570
602
|
ixdsDiscovered = False
|
|
571
|
-
for pluginXbrlMethod in pluginClassMethods("InlineDocumentSet.Discovery"):
|
|
603
|
+
for pluginXbrlMethod in PluginManager.pluginClassMethods("InlineDocumentSet.Discovery"):
|
|
572
604
|
pluginXbrlMethod(filesource, reportEntries)
|
|
573
605
|
ixdsDiscovered = True
|
|
574
606
|
if not ixdsDiscovered and len(reportEntries) > 1:
|
|
@@ -590,13 +622,17 @@ def filesourceEntrypointFiles(filesource, entrypointFiles=None, inlineOnly=False
|
|
|
590
622
|
entrypointFiles.append({"file":url})
|
|
591
623
|
if entrypointFiles:
|
|
592
624
|
if identifiedType == ModelDocument.Type.INLINEXBRL:
|
|
593
|
-
for pluginXbrlMethod in pluginClassMethods("InlineDocumentSet.Discovery"):
|
|
625
|
+
for pluginXbrlMethod in PluginManager.pluginClassMethods("InlineDocumentSet.Discovery"):
|
|
594
626
|
pluginXbrlMethod(filesource, entrypointFiles) # group into IXDS if plugin feature is available
|
|
595
627
|
break # found inline (or non-inline) entrypoint files, don't look for any other type
|
|
596
628
|
# for ESEF non-consolidated xhtml documents accept an xhtml entry point
|
|
597
629
|
if not entrypointFiles and not inlineOnly:
|
|
598
630
|
for url in urlsByType.get(ModelDocument.Type.HTML, []):
|
|
599
631
|
entrypointFiles.append({"file":url})
|
|
632
|
+
if not entrypointFiles and filesource.taxonomyPackage is not None:
|
|
633
|
+
for packageEntry in filesource.taxonomyPackage.get('entryPoints', {}).values():
|
|
634
|
+
for _resolvedUrl, remappedUrl, _closest in packageEntry:
|
|
635
|
+
entrypointFiles.append({"file": remappedUrl})
|
|
600
636
|
|
|
601
637
|
|
|
602
638
|
elif os.path.isdir(filesource.url):
|
|
@@ -611,7 +647,7 @@ def filesourceEntrypointFiles(filesource, entrypointFiles=None, inlineOnly=False
|
|
|
611
647
|
if identifiedType in (ModelDocument.Type.INSTANCE, ModelDocument.Type.INLINEXBRL):
|
|
612
648
|
entrypointFiles.append({"file":_path})
|
|
613
649
|
if hasInline: # group into IXDS if plugin feature is available
|
|
614
|
-
for pluginXbrlMethod in pluginClassMethods("InlineDocumentSet.Discovery"):
|
|
650
|
+
for pluginXbrlMethod in PluginManager.pluginClassMethods("InlineDocumentSet.Discovery"):
|
|
615
651
|
pluginXbrlMethod(filesource, entrypointFiles)
|
|
616
652
|
|
|
617
653
|
return entrypointFiles
|
|
@@ -652,7 +688,7 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
652
688
|
"""
|
|
653
689
|
|
|
654
690
|
def __init__(self, logFileName=None, uiLang=None, disable_persistent_config=False):
|
|
655
|
-
super(
|
|
691
|
+
super().__init__(hasGui=False, uiLang=uiLang, disable_persistent_config=disable_persistent_config)
|
|
656
692
|
self.preloadedPlugins = {}
|
|
657
693
|
|
|
658
694
|
def run(self, options: RuntimeOptions, sourceZipStream=None, responseZipStream=None, sourceZipStreamFileName=None) -> bool:
|
|
@@ -664,24 +700,24 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
664
700
|
:param options: OptionParser options from parse_args of main argv arguments (when called from command line) or corresponding arguments from web service (REST) request.
|
|
665
701
|
:type options: optparse.Values
|
|
666
702
|
"""
|
|
667
|
-
for b in BETA_FEATURES_AND_DESCRIPTIONS
|
|
703
|
+
for b in BETA_FEATURES_AND_DESCRIPTIONS:
|
|
668
704
|
self.betaFeatures[b] = getattr(options, b)
|
|
669
705
|
if options.statusPipe or options.monitorParentProcess:
|
|
670
706
|
try:
|
|
671
707
|
global win32file, win32api, win32process, pywintypes
|
|
672
708
|
import win32file, win32api, win32process, pywintypes
|
|
673
709
|
except ImportError: # win32 not installed
|
|
674
|
-
self.addToLog("--statusPipe {} cannot be installed, packages for win32 missing"
|
|
710
|
+
self.addToLog(f"--statusPipe {options.statusPipe} cannot be installed, packages for win32 missing")
|
|
675
711
|
options.statusPipe = options.monitorParentProcess = None
|
|
676
712
|
if options.statusPipe:
|
|
677
713
|
try:
|
|
678
|
-
self.statusPipe = win32file.CreateFile("\\\\.\\pipe\\{
|
|
714
|
+
self.statusPipe = win32file.CreateFile(f"\\\\.\\pipe\\{options.statusPipe}",
|
|
679
715
|
win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0, None, win32file.OPEN_EXISTING, win32file.FILE_FLAG_NO_BUFFERING, None)
|
|
680
716
|
self.showStatus = self.showStatusOnPipe
|
|
681
717
|
self.lastStatusTime = 0.0
|
|
682
718
|
self.parentProcessHandle = None
|
|
683
719
|
except pywintypes.error: # named pipe doesn't exist
|
|
684
|
-
self.addToLog("--statusPipe {} has not been created by calling program"
|
|
720
|
+
self.addToLog(f"--statusPipe {options.statusPipe} has not been created by calling program")
|
|
685
721
|
if options.monitorParentProcess:
|
|
686
722
|
try:
|
|
687
723
|
self.parentProcessHandle = win32api.OpenProcess(PROCESS_QUERY_INFORMATION, False, int(options.monitorParentProcess))
|
|
@@ -693,14 +729,14 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
693
729
|
_t.start()
|
|
694
730
|
monitorParentProcess()
|
|
695
731
|
except ImportError: # win32 not installed
|
|
696
|
-
self.addToLog("--monitorParentProcess {} cannot be installed, packages for win32api and win32process missing"
|
|
732
|
+
self.addToLog(f"--monitorParentProcess {options.monitorParentProcess} cannot be installed, packages for win32api and win32process missing")
|
|
697
733
|
except (ValueError, pywintypes.error): # parent process doesn't exist
|
|
698
|
-
self.addToLog("--monitorParentProcess Process {} Id is invalid"
|
|
734
|
+
self.addToLog(f"--monitorParentProcess Process {options.monitorParentProcess} Id is invalid")
|
|
699
735
|
sys.exit()
|
|
700
736
|
if options.showOptions: # debug options
|
|
701
737
|
for optName, optValue in sorted(options.__dict__.items(), key=lambda optItem: optItem[0]):
|
|
702
|
-
self.addToLog("Option {
|
|
703
|
-
self.addToLog("sys.argv {
|
|
738
|
+
self.addToLog(f"Option {optName}={optValue}", messageCode="info")
|
|
739
|
+
self.addToLog(f"sys.argv {sys.argv}", messageCode="info")
|
|
704
740
|
|
|
705
741
|
setDisableRTL(options.disableRtl) # not saved to config
|
|
706
742
|
|
|
@@ -730,7 +766,7 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
730
766
|
":****" if password else "",
|
|
731
767
|
"@" if (user or password) else "",
|
|
732
768
|
urlAddr,
|
|
733
|
-
":{
|
|
769
|
+
f":{urlPort}" if urlPort else ""), messageCode="info")
|
|
734
770
|
else:
|
|
735
771
|
self.addToLog(_("Proxy is disabled."), messageCode="info")
|
|
736
772
|
if options.noCertificateCheck:
|
|
@@ -801,7 +837,7 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
801
837
|
if loadPluginOptions:
|
|
802
838
|
_optionsParser = ParserForDynamicPlugins(options)
|
|
803
839
|
# add plug-in options
|
|
804
|
-
for optionsExtender in pluginClassMethods("CntlrCmdLine.Options"):
|
|
840
|
+
for optionsExtender in PluginManager.pluginClassMethods("CntlrCmdLine.Options"):
|
|
805
841
|
optionsExtender(_optionsParser)
|
|
806
842
|
|
|
807
843
|
if showPluginModules:
|
|
@@ -844,6 +880,8 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
844
880
|
else:
|
|
845
881
|
self.modelManager.disclosureSystem.select(None) # just load ordinary mappings
|
|
846
882
|
self.modelManager.validateDisclosureSystem = False
|
|
883
|
+
if options.baseTaxonomyValidationMode is not None:
|
|
884
|
+
self.modelManager.baseTaxonomyValidationMode = ValidateBaseTaxonomiesMode.fromName(options.baseTaxonomyValidationMode)
|
|
847
885
|
self.modelManager.validateXmlOim = bool(options.validateXmlOim)
|
|
848
886
|
if options.validateDuplicateFacts:
|
|
849
887
|
duplicateTypeArg = ValidateDuplicateFacts.DuplicateTypeArg(options.validateDuplicateFacts)
|
|
@@ -981,7 +1019,7 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
981
1019
|
|
|
982
1020
|
# run utility command line options that don't depend on entrypoint Files
|
|
983
1021
|
hasUtilityPlugin = False
|
|
984
|
-
for pluginXbrlMethod in pluginClassMethods("CntlrCmdLine.Utility.Run"):
|
|
1022
|
+
for pluginXbrlMethod in PluginManager.pluginClassMethods("CntlrCmdLine.Utility.Run"):
|
|
985
1023
|
hasUtilityPlugin = True
|
|
986
1024
|
try:
|
|
987
1025
|
pluginXbrlMethod(self, options, sourceZipStream=sourceZipStream, responseZipStream=responseZipStream)
|
|
@@ -1006,7 +1044,7 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
1006
1044
|
except ValueError as e:
|
|
1007
1045
|
# is it malformed json?
|
|
1008
1046
|
if _f.startswith("[{") or _f.endswith("]}") or '"file:"' in _f:
|
|
1009
|
-
self.addToLog(_("File name parameter appears to be malformed JSON: {
|
|
1047
|
+
self.addToLog(_("File name parameter appears to be malformed JSON: {}\n{}").format(e, _f),
|
|
1010
1048
|
messageCode="FileNameFormatError",
|
|
1011
1049
|
level=logging.ERROR)
|
|
1012
1050
|
success = False
|
|
@@ -1029,9 +1067,9 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
1029
1067
|
self.addToLog(str(err), messageCode="error", level=logging.ERROR)
|
|
1030
1068
|
return False
|
|
1031
1069
|
|
|
1032
|
-
for pluginXbrlMethod in pluginClassMethods("CntlrCmdLine.Filing.Start"):
|
|
1070
|
+
for pluginXbrlMethod in PluginManager.pluginClassMethods("CntlrCmdLine.Filing.Start"):
|
|
1033
1071
|
pluginXbrlMethod(self, options, filesource, _entrypointFiles, sourceZipStream=sourceZipStream, responseZipStream=responseZipStream)
|
|
1034
|
-
if len(_entrypointFiles) == 0:
|
|
1072
|
+
if len(_entrypointFiles) == 0 and not options.packages:
|
|
1035
1073
|
if options.entrypointFile:
|
|
1036
1074
|
msg = _("No XBRL entry points could be loaded from provided file: {}").format(options.entrypointFile)
|
|
1037
1075
|
else:
|
|
@@ -1090,10 +1128,10 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
1090
1128
|
if modelXbrl.errors:
|
|
1091
1129
|
success = False # loading errors, don't attempt to utilize loaded DTS
|
|
1092
1130
|
if modelXbrl.modelDocument.type in ModelDocument.Type.TESTCASETYPES:
|
|
1093
|
-
for pluginXbrlMethod in pluginClassMethods("Testcases.Start"):
|
|
1131
|
+
for pluginXbrlMethod in PluginManager.pluginClassMethods("Testcases.Start"):
|
|
1094
1132
|
pluginXbrlMethod(self, options, modelXbrl)
|
|
1095
1133
|
else: # not a test case, probably instance or DTS
|
|
1096
|
-
for pluginXbrlMethod in pluginClassMethods("CntlrCmdLine.Xbrl.Loaded"):
|
|
1134
|
+
for pluginXbrlMethod in PluginManager.pluginClassMethods("CntlrCmdLine.Xbrl.Loaded"):
|
|
1097
1135
|
pluginXbrlMethod(self, options, modelXbrl, _entrypoint, responseZipStream=responseZipStream)
|
|
1098
1136
|
if options.saveOIMToXMLReport:
|
|
1099
1137
|
if modelXbrl.loadedFromOIM and modelXbrl.modelDocument is not None:
|
|
@@ -1142,7 +1180,7 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
1142
1180
|
for modelXbrl in [self.modelManager.modelXbrl] + getattr(self.modelManager.modelXbrl, "supplementalModelXbrls", []):
|
|
1143
1181
|
hasFormulae = modelXbrl.hasFormulae
|
|
1144
1182
|
isAlreadyValidated = False
|
|
1145
|
-
for pluginXbrlMethod in pluginClassMethods("ModelDocument.IsValidated"):
|
|
1183
|
+
for pluginXbrlMethod in PluginManager.pluginClassMethods("ModelDocument.IsValidated"):
|
|
1146
1184
|
if pluginXbrlMethod(modelXbrl): # e.g., streaming extensions already has validated
|
|
1147
1185
|
isAlreadyValidated = True
|
|
1148
1186
|
if options.validate and not isAlreadyValidated:
|
|
@@ -1208,10 +1246,10 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
1208
1246
|
if options.arcroleTypesFile:
|
|
1209
1247
|
ViewFileRoleTypes.viewRoleTypes(modelXbrl, options.arcroleTypesFile, "Arcrole Types", isArcrole=True, lang=options.labelLang)
|
|
1210
1248
|
|
|
1211
|
-
for pluginXbrlMethod in pluginClassMethods("CntlrCmdLine.Xbrl.Run"):
|
|
1249
|
+
for pluginXbrlMethod in PluginManager.pluginClassMethods("CntlrCmdLine.Xbrl.Run"):
|
|
1212
1250
|
pluginXbrlMethod(self, options, modelXbrl, _entrypoint, sourceZipStream=sourceZipStream, responseZipStream=responseZipStream)
|
|
1213
1251
|
|
|
1214
|
-
except
|
|
1252
|
+
except OSError as err:
|
|
1215
1253
|
self.addToLog(_("[IOError] Failed to save output:\n {0}").format(err),
|
|
1216
1254
|
messageCode="IOError",
|
|
1217
1255
|
file=options.entrypointFile,
|
|
@@ -1258,15 +1296,15 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
1258
1296
|
self.modelManager.close(modelDiffReport)
|
|
1259
1297
|
elif modelXbrl:
|
|
1260
1298
|
self.modelManager.close(modelXbrl)
|
|
1261
|
-
if not options.keepOpen:
|
|
1299
|
+
if filesource is not None and not options.keepOpen:
|
|
1262
1300
|
# Archive filesource potentially used by multiple reports may still be open.
|
|
1263
1301
|
filesource.close()
|
|
1264
1302
|
|
|
1265
1303
|
if success:
|
|
1266
1304
|
if options.validate:
|
|
1267
|
-
for pluginXbrlMethod in pluginClassMethods("CntlrCmdLine.Filing.Validate"):
|
|
1305
|
+
for pluginXbrlMethod in PluginManager.pluginClassMethods("CntlrCmdLine.Filing.Validate"):
|
|
1268
1306
|
pluginXbrlMethod(self, options, filesource, _entrypointFiles, sourceZipStream=sourceZipStream, responseZipStream=responseZipStream)
|
|
1269
|
-
for pluginXbrlMethod in pluginClassMethods("CntlrCmdLine.Filing.End"):
|
|
1307
|
+
for pluginXbrlMethod in PluginManager.pluginClassMethods("CntlrCmdLine.Filing.End"):
|
|
1270
1308
|
pluginXbrlMethod(self, options, filesource, _entrypointFiles, sourceZipStream=sourceZipStream, responseZipStream=responseZipStream)
|
|
1271
1309
|
self.username = self.password = None #dereference password
|
|
1272
1310
|
self._clearPluginData()
|
arelle/CntlrWinMain.py
CHANGED
|
@@ -34,6 +34,7 @@ from arelle import XbrlConst
|
|
|
34
34
|
from arelle.PluginManager import pluginClassMethods
|
|
35
35
|
from arelle.UrlUtil import isHttpUrl
|
|
36
36
|
from arelle.ValidateXbrlCalcs import ValidateCalcsMode as CalcsMode
|
|
37
|
+
from arelle.ValidateXbrlDTS import ValidateBaseTaxonomiesMode
|
|
37
38
|
from arelle.Version import copyrightLabel
|
|
38
39
|
from arelle.oim.xml.Save import saveOimReportToXmlInstance
|
|
39
40
|
import logging
|
|
@@ -164,6 +165,16 @@ class CntlrWinMain (Cntlr.Cntlr):
|
|
|
164
165
|
for calcChoiceMenuLabel, calcChoiceEnumValue in CalcsMode.menu().items():
|
|
165
166
|
calcMenu.add_radiobutton(label=calcChoiceMenuLabel, underline=0, var=self.calcChoiceEnumVar, value=calcChoiceEnumValue)
|
|
166
167
|
toolsMenu.add_cascade(label=_("Calc linkbase"), menu=calcMenu, underline=0)
|
|
168
|
+
|
|
169
|
+
baseValidateModeMenu = Menu(self.menubar, tearoff=0)
|
|
170
|
+
baseValidationModeName = self.config.setdefault("baseTaxonomyValidationMode", ValidateBaseTaxonomiesMode.DISCLOSURE_SYSTEM.value)
|
|
171
|
+
self.modelManager.baseTaxonomyValidationMode = ValidateBaseTaxonomiesMode.fromName(baseValidationModeName)
|
|
172
|
+
self.baseTaxonomyValidationModeEnumVar = StringVar(self.parent, value=baseValidationModeName)
|
|
173
|
+
self.baseTaxonomyValidationModeEnumVar.trace("w", self.setBaseTaxonomyValidationModeEnumVar)
|
|
174
|
+
for modeLabel, modeValue in ValidateBaseTaxonomiesMode.menu().items():
|
|
175
|
+
baseValidateModeMenu.add_radiobutton(label=modeLabel, underline=0, var=self.baseTaxonomyValidationModeEnumVar, value=modeValue)
|
|
176
|
+
validateMenu.add_cascade(label=_("Base taxonomy validation"), menu=baseValidateModeMenu, underline=0)
|
|
177
|
+
|
|
167
178
|
self.modelManager.validateUtr = self.config.setdefault("validateUtr",True)
|
|
168
179
|
self.validateUtr = BooleanVar(value=self.modelManager.validateUtr)
|
|
169
180
|
self.validateUtr.trace("w", self.setValidateUtr)
|
|
@@ -670,7 +681,16 @@ class CntlrWinMain (Cntlr.Cntlr):
|
|
|
670
681
|
elif isinstance(view, ViewWinDTS.ViewDTS):
|
|
671
682
|
ViewFileDTS.viewDTS(modelXbrl, filename)
|
|
672
683
|
else:
|
|
673
|
-
|
|
684
|
+
if isinstance(view.arcrole, tuple) and len(view.arcrole) > 0 and view.arcrole[0] == "Calculation":
|
|
685
|
+
# "arcrole" is overloaded with special strings that are sometimes used magically to query
|
|
686
|
+
# the model and other times just to provide a header value. In the case of Calculation, it's
|
|
687
|
+
# only the header used in the GUI view and including it here when going to save will throw
|
|
688
|
+
# an exception.
|
|
689
|
+
arcrole = XbrlConst.summationItems
|
|
690
|
+
else:
|
|
691
|
+
arcrole = view.arcrole
|
|
692
|
+
|
|
693
|
+
ViewFileRelationshipSet.viewRelationshipSet(modelXbrl, filename, view.tabTitle, arcrole, labelrole=view.labelrole, lang=view.lang)
|
|
674
694
|
except (IOError, EnvironmentError) as err:
|
|
675
695
|
tkinter.messagebox.showwarning(_("arelle - Error"),
|
|
676
696
|
_("Failed to save {0}:\n{1}").format(
|
|
@@ -977,7 +997,7 @@ class CntlrWinMain (Cntlr.Cntlr):
|
|
|
977
997
|
hasView = ViewWinRelationshipSet.viewRelationshipSet(modelXbrl, self.tabWinTopRt, XbrlConst.parentChild, lang=self.labelLang)
|
|
978
998
|
if hasView and topView is None: topView = modelXbrl.views[-1]
|
|
979
999
|
currentAction = "calculation linkbase view"
|
|
980
|
-
hasView = ViewWinRelationshipSet.viewRelationshipSet(modelXbrl, self.tabWinTopRt, ("Calculation",
|
|
1000
|
+
hasView = ViewWinRelationshipSet.viewRelationshipSet(modelXbrl, self.tabWinTopRt, ("Calculation", XbrlConst.summationItems), lang=self.labelLang)
|
|
981
1001
|
if hasView and topView is None: topView = modelXbrl.views[-1]
|
|
982
1002
|
currentAction = "dimensions relationships view"
|
|
983
1003
|
hasView = ViewWinRelationshipSet.viewRelationshipSet(modelXbrl, self.tabWinTopRt, "XBRL-dimensions", lang=self.labelLang)
|
|
@@ -1401,6 +1421,13 @@ class CntlrWinMain (Cntlr.Cntlr):
|
|
|
1401
1421
|
self.saveConfig()
|
|
1402
1422
|
self.setValidateTooltipText()
|
|
1403
1423
|
|
|
1424
|
+
def setBaseTaxonomyValidationModeEnumVar(self, *args):
|
|
1425
|
+
modeName = self.baseTaxonomyValidationModeEnumVar.get()
|
|
1426
|
+
self.modelManager.baseTaxonomyValidationMode = ValidateBaseTaxonomiesMode.fromName(modeName)
|
|
1427
|
+
self.config["baseTaxonomyValidationMode"] = modeName
|
|
1428
|
+
self.saveConfig()
|
|
1429
|
+
self.setValidateTooltipText()
|
|
1430
|
+
|
|
1404
1431
|
def setValidateUtr(self, *args):
|
|
1405
1432
|
self.modelManager.validateUtr = self.validateUtr.get()
|
|
1406
1433
|
self.config["validateUtr"] = self.modelManager.validateUtr
|
arelle/ModelManager.py
CHANGED
|
@@ -9,6 +9,7 @@ import gc, sys, traceback, logging
|
|
|
9
9
|
from arelle import ModelXbrl, Validate, DisclosureSystem, PackageManager, ValidateXbrlCalcs, ValidateDuplicateFacts
|
|
10
10
|
from arelle.ModelFormulaObject import FormulaOptions
|
|
11
11
|
from arelle.PluginManager import pluginClassMethods
|
|
12
|
+
from arelle.ValidateXbrlDTS import ValidateBaseTaxonomiesMode
|
|
12
13
|
from arelle.typing import LocaleDict
|
|
13
14
|
|
|
14
15
|
if TYPE_CHECKING:
|
|
@@ -67,6 +68,7 @@ class ModelManager:
|
|
|
67
68
|
self.loadedModelXbrls = []
|
|
68
69
|
self.customTransforms: dict[QName, Callable[[str], str]] | None = None
|
|
69
70
|
self.isLocaleSet = False
|
|
71
|
+
self.baseTaxonomyValidationMode = ValidateBaseTaxonomiesMode.DISCLOSURE_SYSTEM
|
|
70
72
|
self.validateAllFilesAsReportPackages = False
|
|
71
73
|
self.validateDuplicateFacts = ValidateDuplicateFacts.DuplicateType.NONE
|
|
72
74
|
self.validateXmlOim = False
|
arelle/ModelValue.py
CHANGED
|
@@ -277,10 +277,11 @@ def tzinfo(tz: str | None) -> datetime.timezone | None:
|
|
|
277
277
|
else:
|
|
278
278
|
return datetime.timezone(datetime.timedelta(hours=int(tz[0:3]), minutes=int(tz[0]+tz[4:6])))
|
|
279
279
|
|
|
280
|
-
def tzinfoStr(dt: datetime.datetime) -> str:
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
280
|
+
def tzinfoStr(dt: datetime.datetime | datetime.date) -> str:
|
|
281
|
+
if isinstance(dt, datetime.datetime):
|
|
282
|
+
tz = str(dt.tzinfo or "")
|
|
283
|
+
if tz.startswith("UTC"):
|
|
284
|
+
return tz[3:] or "Z"
|
|
284
285
|
return ""
|
|
285
286
|
|
|
286
287
|
def dateTime(
|
arelle/RuntimeOptions.py
CHANGED
|
@@ -33,6 +33,7 @@ class RuntimeOptions:
|
|
|
33
33
|
about: Optional[str] = None
|
|
34
34
|
anchFile: Optional[str] = None
|
|
35
35
|
arcroleTypesFile: Optional[str] = None
|
|
36
|
+
baseTaxonomyValidationMode: Optional[str] = None
|
|
36
37
|
betaObjectModel: Optional[bool] = False
|
|
37
38
|
cacheDirectory: Optional[str] = None
|
|
38
39
|
calFile: Optional[str] = None
|
arelle/ValidateXbrlDTS.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
See COPYRIGHT.md for copyright information.
|
|
3
3
|
'''
|
|
4
4
|
from __future__ import annotations
|
|
5
|
+
from enum import Enum, auto
|
|
5
6
|
from typing import TYPE_CHECKING
|
|
6
7
|
from arelle import (ModelDocument, ModelDtsObject, HtmlUtil, UrlUtil, XmlUtil, XbrlUtil, XbrlConst,
|
|
7
8
|
XmlValidate)
|
|
@@ -49,6 +50,37 @@ inlineDisplayNonePattern = re.compile(r"display\s*:\s*none")
|
|
|
49
50
|
# lookbehind below is to ignore even numbers of \ before illegal escape character
|
|
50
51
|
illegalXsdPatternEscapeChar = re.compile(r"(?:(?:^|[^\\])(?:\\\\)*)(\\[^nrt\\|.^?*+{}()[\]pPsSiIcCdDwW-])")
|
|
51
52
|
|
|
53
|
+
class ValidateBaseTaxonomiesMode(Enum):
|
|
54
|
+
DISCLOSURE_SYSTEM = "disclosureSystem"
|
|
55
|
+
NONE = "none"
|
|
56
|
+
ALL = "all"
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def fromName(modeName: str) -> ValidateBaseTaxonomiesMode:
|
|
60
|
+
for mode in ValidateBaseTaxonomiesMode:
|
|
61
|
+
if mode.value == modeName:
|
|
62
|
+
return mode
|
|
63
|
+
raise ValueError(f"Unknown ValidateBaseTaxonomiesMode: {modeName}")
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def tooltip(enum: ValidateBaseTaxonomiesMode):
|
|
67
|
+
if enum == ValidateBaseTaxonomiesMode.DISCLOSURE_SYSTEM:
|
|
68
|
+
return _("Skip validation of base taxonomy files which are known to be valid by the disclosure system")
|
|
69
|
+
if enum == ValidateBaseTaxonomiesMode.NONE:
|
|
70
|
+
return _("Skip validation of all base taxonomy files")
|
|
71
|
+
if enum == ValidateBaseTaxonomiesMode.ALL:
|
|
72
|
+
return _("Validate all base taxonomy files")
|
|
73
|
+
raise ValueError(f"Unknown ValidateBaseTaxonomiesMode: {enum}")
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def menu():
|
|
77
|
+
return {
|
|
78
|
+
_("Use disclosure system settings"): ValidateBaseTaxonomiesMode.DISCLOSURE_SYSTEM.value,
|
|
79
|
+
_("Don't validate any base files"): ValidateBaseTaxonomiesMode.NONE.value,
|
|
80
|
+
_("Validate all base files"): ValidateBaseTaxonomiesMode.ALL.value,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
52
84
|
def arcFromConceptQname(arcElement):
|
|
53
85
|
modelRelationship = baseSetRelationship(arcElement)
|
|
54
86
|
if modelRelationship is None:
|
|
@@ -261,36 +293,42 @@ def checkDTS(val: ValidateXbrl, modelDocument: ModelDocument.ModelDocument, chec
|
|
|
261
293
|
# XML validation checks (remove if using validating XML)
|
|
262
294
|
val.extendedElementName = None
|
|
263
295
|
isFilingDocument = False
|
|
264
|
-
# validate contents of entry point document or its sibling/descendant documents or in report package of entry point
|
|
265
|
-
if ((modelDocument.uri.startswith(val.modelXbrl.uriDir) or # document uri in same subtree as entry doocument
|
|
266
|
-
(val.modelXbrl.fileSource.isOpen and modelDocument.filepath.startswith(val.modelXbrl.fileSource.baseurl))) and # document in entry submission's package
|
|
267
|
-
modelDocument.targetNamespace not in val.disclosureSystem.baseTaxonomyNamespaces and
|
|
268
|
-
modelDocument.xmlDocument):
|
|
269
|
-
isFilingDocument = True
|
|
270
|
-
val.valUsedPrefixes = set()
|
|
271
|
-
val.schemaRoleTypes = {}
|
|
272
|
-
val.schemaArcroleTypes = {}
|
|
273
|
-
val.referencedNamespaces = set()
|
|
274
296
|
|
|
275
|
-
|
|
297
|
+
if modelDocument.xmlDocument is not None:
|
|
298
|
+
isExtensionTaxonomyDoc = _isExtensionTaxonomyDocument(val, modelDocument)
|
|
299
|
+
if isExtensionTaxonomyDoc or _shouldValidateBaseTaxonomyDoc(val, modelDocument):
|
|
300
|
+
isFilingDocument = True
|
|
301
|
+
val.valUsedPrefixes = set()
|
|
302
|
+
val.schemaRoleTypes = {}
|
|
303
|
+
val.schemaArcroleTypes = {}
|
|
304
|
+
val.referencedNamespaces = set()
|
|
276
305
|
|
|
277
|
-
|
|
306
|
+
val.containsRelationship = False
|
|
278
307
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
(
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
308
|
+
checkElements(val, modelDocument, modelDocument.xmlDocument)
|
|
309
|
+
|
|
310
|
+
if (modelDocument.type == ModelDocument.Type.INLINEXBRL and
|
|
311
|
+
val.validateGFM and
|
|
312
|
+
(val.documentTypeEncoding.lower() != 'utf-8' or val.metaContentTypeEncoding.lower() != 'utf-8')):
|
|
313
|
+
val.modelXbrl.error("GFM.1.10.4",
|
|
314
|
+
_("XML declaration encoding %(encoding)s and meta content type encoding %(metaContentTypeEncoding)s must both be utf-8"),
|
|
315
|
+
modelXbrl=modelDocument, encoding=val.documentTypeEncoding,
|
|
316
|
+
metaContentTypeEncoding=val.metaContentTypeEncoding)
|
|
317
|
+
if val.validateSBRNL:
|
|
318
|
+
for pluginXbrlMethod in pluginClassMethods("Validate.SBRNL.DTS.document"):
|
|
319
|
+
pluginXbrlMethod(val, modelDocument)
|
|
320
|
+
del val.valUsedPrefixes
|
|
321
|
+
del val.schemaRoleTypes
|
|
322
|
+
del val.schemaArcroleTypes
|
|
323
|
+
|
|
324
|
+
if isExtensionTaxonomyDoc:
|
|
325
|
+
# While not captured in the hook name, the Validate.XBRL.DTS.document hook has been historically used by
|
|
326
|
+
# plugins (see EDGAR plugin) to validate extension taxonomies. This worked because Arelle didn't fully
|
|
327
|
+
# validate base taxonomy documents. Although Arelle now validates all documents, it retains this logic for
|
|
328
|
+
# the plugin hook to prevent running validation rules intended solely for extension taxonomy documents
|
|
329
|
+
# against base taxonomy documents.
|
|
330
|
+
for pluginXbrlMethod in pluginClassMethods("Validate.XBRL.DTS.document"):
|
|
331
|
+
pluginXbrlMethod(val, modelDocument, isFilingDocument)
|
|
294
332
|
|
|
295
333
|
val.roleRefURIs = None
|
|
296
334
|
val.arcroleRefURIs = None
|
|
@@ -1388,3 +1426,21 @@ def checkIxContinuationChain(val, elt, chain=None):
|
|
|
1388
1426
|
if contAt is not None:
|
|
1389
1427
|
chain.append(elt)
|
|
1390
1428
|
checkIxContinuationChain(val, contAt, chain)
|
|
1429
|
+
|
|
1430
|
+
def _isExtensionTaxonomyDocument(val: ValidateXbrl, modelDocument: ModelDocument.ModelDocument) -> bool:
|
|
1431
|
+
if modelDocument.uri.startswith(val.modelXbrl.uriDir):
|
|
1432
|
+
# document uri in same subtree as entry doocument.
|
|
1433
|
+
return True
|
|
1434
|
+
|
|
1435
|
+
# check if document in entry submission's package.
|
|
1436
|
+
return val.modelXbrl.fileSource.isOpen and modelDocument.filepath.startswith(val.modelXbrl.fileSource.baseurl)
|
|
1437
|
+
|
|
1438
|
+
def _shouldValidateBaseTaxonomyDoc(val: ValidateXbrl, modelDocument: ModelDocument.ModelDocument) -> bool:
|
|
1439
|
+
baseTaxonomyValidationMode = val.modelXbrl.modelManager.baseTaxonomyValidationMode
|
|
1440
|
+
if baseTaxonomyValidationMode == ValidateBaseTaxonomiesMode.NONE:
|
|
1441
|
+
return False
|
|
1442
|
+
if baseTaxonomyValidationMode == ValidateBaseTaxonomiesMode.ALL:
|
|
1443
|
+
return True
|
|
1444
|
+
if baseTaxonomyValidationMode == ValidateBaseTaxonomiesMode.DISCLOSURE_SYSTEM:
|
|
1445
|
+
return modelDocument.uri not in getattr(val.disclosureSystem, "standardTaxonomiesDict", {})
|
|
1446
|
+
raise ValueError(f"Invalid base taxonomy validation mode: {baseTaxonomyValidationMode}")
|
|
@@ -31,8 +31,10 @@ COL_WIDTHS = {
|
|
|
31
31
|
"Name": 40, "Namespace": 60, "LocalName": 40, "Documentation": 80
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
def hasCalcArcrole(arcroles: tuple[str] | str) -> bool:
|
|
35
|
-
|
|
34
|
+
def hasCalcArcrole(arcroles: tuple[str | tuple[str, ...], ...] | str) -> bool:
|
|
35
|
+
if isinstance(arcroles, (tuple, list)):
|
|
36
|
+
return any(hasCalcArcrole(arcrole) for arcrole in arcroles)
|
|
37
|
+
return arcroles in XbrlConst.summationItems
|
|
36
38
|
|
|
37
39
|
class ViewRelationshipSet(ViewFile.View):
|
|
38
40
|
def __init__(self, modelXbrl, outfile, header, labelrole, lang, cols):
|
arelle/ViewFileRenderedGrid.py
CHANGED
|
@@ -16,7 +16,7 @@ from arelle.ModelRenderingObject import (StrctMdlBreakdown, StrctMdlStructuralNo
|
|
|
16
16
|
OPEN_ASPECT_ENTRY_SURROGATE, ROLLUP_SPECIFIES_MEMBER, ROLLUP_FOR_DIMENSION_RELATIONSHIP_NODE,
|
|
17
17
|
aspectStrctNodes)
|
|
18
18
|
from arelle.rendering.RenderingLayout import layoutTable
|
|
19
|
-
from arelle.rendering.RenderingResolution import
|
|
19
|
+
from arelle.rendering.RenderingResolution import RENDER_UNITS_PER_CHAR
|
|
20
20
|
from arelle.ModelValue import QName
|
|
21
21
|
from arelle.ModelXbrl import DEFAULT
|
|
22
22
|
from arelle.ViewFile import HTML, XML
|
arelle/ViewFileRenderedLayout.py
CHANGED
|
@@ -10,7 +10,6 @@ from arelle import ViewFile
|
|
|
10
10
|
from arelle.FunctionXs import xsString
|
|
11
11
|
from arelle.ModelObject import ModelObject
|
|
12
12
|
from arelle.Aspect import Aspect, aspectModels, aspectRuleAspects, aspectModelAspect, aspectStr
|
|
13
|
-
from arelle.rendering.RenderingResolution import resolveTableStructure
|
|
14
13
|
from arelle.rendering.RenderingLayout import layoutTable
|
|
15
14
|
from arelle import XbrlConst
|
|
16
15
|
from arelle.XmlUtil import elementFragmentIdentifier, addQnameValue
|