arelle-release 2.36.29__py3-none-any.whl → 2.36.31__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 +88 -50
- arelle/CntlrWinMain.py +18 -0
- arelle/ModelManager.py +2 -0
- arelle/ModelValue.py +5 -4
- arelle/RuntimeOptions.py +1 -0
- arelle/ValidateXbrlDTS.py +83 -27
- arelle/ViewFileRenderedGrid.py +1 -1
- arelle/ViewFileRenderedLayout.py +0 -1
- arelle/ViewWinRenderedGrid.py +1 -1
- arelle/XmlUtil.py +1 -1
- arelle/_version.py +2 -2
- arelle/plugin/saveLoadableOIM.py +38 -5
- arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py +1 -1
- arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py +1 -1
- arelle/rendering/RenderingResolution.py +2 -2
- {arelle_release-2.36.29.dist-info → arelle_release-2.36.31.dist-info}/METADATA +1 -1
- {arelle_release-2.36.29.dist-info → arelle_release-2.36.31.dist-info}/RECORD +42 -42
- 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.29.dist-info → arelle_release-2.36.31.dist-info}/LICENSE.md +0 -0
- {arelle_release-2.36.29.dist-info → arelle_release-2.36.31.dist-info}/WHEEL +0 -0
- {arelle_release-2.36.29.dist-info → arelle_release-2.36.31.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.36.29.dist-info → arelle_release-2.36.31.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,7 +1067,7 @@ 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
1072
|
if len(_entrypointFiles) == 0:
|
|
1035
1073
|
if options.entrypointFile:
|
|
@@ -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,
|
|
@@ -1264,9 +1302,9 @@ class CntlrCmdLine(Cntlr.Cntlr):
|
|
|
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)
|
|
@@ -1401,6 +1412,13 @@ class CntlrWinMain (Cntlr.Cntlr):
|
|
|
1401
1412
|
self.saveConfig()
|
|
1402
1413
|
self.setValidateTooltipText()
|
|
1403
1414
|
|
|
1415
|
+
def setBaseTaxonomyValidationModeEnumVar(self, *args):
|
|
1416
|
+
modeName = self.baseTaxonomyValidationModeEnumVar.get()
|
|
1417
|
+
self.modelManager.baseTaxonomyValidationMode = ValidateBaseTaxonomiesMode.fromName(modeName)
|
|
1418
|
+
self.config["baseTaxonomyValidationMode"] = modeName
|
|
1419
|
+
self.saveConfig()
|
|
1420
|
+
self.setValidateTooltipText()
|
|
1421
|
+
|
|
1404
1422
|
def setValidateUtr(self, *args):
|
|
1405
1423
|
self.modelManager.validateUtr = self.validateUtr.get()
|
|
1406
1424
|
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}")
|
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
|
arelle/ViewWinRenderedGrid.py
CHANGED
|
@@ -8,7 +8,7 @@ from arelle import (ViewWinTkTable, ModelDocument, ModelDtsObject, ModelInstance
|
|
|
8
8
|
ModelXbrl, Locale, FunctionXfi,
|
|
9
9
|
ValidateXbrlDimensions, ViewFileRenderedGrid, ViewFileRenderedLayout, ViewFileRenderedStructure)
|
|
10
10
|
from arelle.ModelValue import qname, QName
|
|
11
|
-
from arelle.rendering.RenderingResolution import
|
|
11
|
+
from arelle.rendering.RenderingResolution import RENDER_UNITS_PER_CHAR
|
|
12
12
|
from arelle.rendering.RenderingLayout import layoutTable
|
|
13
13
|
from arelle.ModelInstanceObject import ModelDimensionValue
|
|
14
14
|
from arelle.ModelRenderingObject import (StrctMdlBreakdown, DefnMdlDefinitionNode,
|
arelle/XmlUtil.py
CHANGED
|
@@ -1035,7 +1035,7 @@ def dateunionValue(
|
|
|
1035
1035
|
) -> str:
|
|
1036
1036
|
if not isinstance(datetimeValue, (datetime.datetime, datetime.date)):
|
|
1037
1037
|
return "INVALID"
|
|
1038
|
-
tz = tzinfoStr(datetimeValue)
|
|
1038
|
+
tz = tzinfoStr(datetimeValue)
|
|
1039
1039
|
isDate = getattr(
|
|
1040
1040
|
datetimeValue, 'dateOnly', False) or not hasattr(datetimeValue, 'hour')
|
|
1041
1041
|
if isDate or (
|
arelle/_version.py
CHANGED
arelle/plugin/saveLoadableOIM.py
CHANGED
|
@@ -30,6 +30,17 @@ allowing for efficient data handling in Arelle.
|
|
|
30
30
|
python arelleCmdLine.py --plugins saveLoadableOIM --file filing-documents.zip --saveTestcaseOimFileSuffix -savedOim.csv
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
- **Deduplicate facts**
|
|
34
|
+
To save an OIM instance with duplicate fact removed use the `--deduplicateOimFacts` argument with either `complete`,
|
|
35
|
+
`consistent-pairs`, or `consistent-sets` as the value.
|
|
36
|
+
For details on what eaxctly consitutes a duplicate fact and why there are multiple options read the
|
|
37
|
+
[Fact Deduplication][fact-deduplication] documentation.
|
|
38
|
+
```bash
|
|
39
|
+
python arelleCmdLine.py --plugins saveLoadableOIM --file filing-documents.zip --saveLoadableOIM example.json --deduplicateOimFacts complete
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
[fact-deduplication]: project:/user_guides/fact_deduplication.md
|
|
43
|
+
|
|
33
44
|
### GUI Usage
|
|
34
45
|
|
|
35
46
|
- **Save Re-Loadable Output**:
|
|
@@ -51,6 +62,7 @@ import json
|
|
|
51
62
|
import os
|
|
52
63
|
import threading
|
|
53
64
|
import zipfile
|
|
65
|
+
from collections.abc import Iterable
|
|
54
66
|
from dataclasses import dataclass
|
|
55
67
|
from datetime import datetime
|
|
56
68
|
from decimal import Decimal
|
|
@@ -58,7 +70,7 @@ from math import isinf, isnan
|
|
|
58
70
|
from numbers import Number
|
|
59
71
|
from optparse import OptionParser
|
|
60
72
|
from pathlib import Path
|
|
61
|
-
from typing import TYPE_CHECKING, Any, BinaryIO, Callable,
|
|
73
|
+
from typing import TYPE_CHECKING, Any, BinaryIO, Callable, Optional, cast
|
|
62
74
|
|
|
63
75
|
import regex as re
|
|
64
76
|
from openpyxl import Workbook
|
|
@@ -66,7 +78,7 @@ from openpyxl.cell.cell import WriteOnlyCell
|
|
|
66
78
|
from openpyxl.styles import Alignment, Color, PatternFill, fills
|
|
67
79
|
from openpyxl.worksheet.dimensions import ColumnDimension
|
|
68
80
|
|
|
69
|
-
from arelle import ModelDocument, XbrlConst
|
|
81
|
+
from arelle import ModelDocument, ValidateDuplicateFacts, XbrlConst
|
|
70
82
|
from arelle.ModelInstanceObject import ModelContext, ModelFact
|
|
71
83
|
from arelle.ModelRelationshipSet import ModelRelationshipSet
|
|
72
84
|
from arelle.ModelValue import (
|
|
@@ -446,6 +458,16 @@ def saveLoadableOIM(
|
|
|
446
458
|
if isJSON:
|
|
447
459
|
oimFeatures["xbrl:canonicalValues"] = True
|
|
448
460
|
|
|
461
|
+
factsToSave = modelXbrl.facts
|
|
462
|
+
pluginData = modelXbrl.modelManager.cntlr.getPluginData(PLUGIN_NAME)
|
|
463
|
+
if isinstance(pluginData, SaveLoadableOIMPluginData) and pluginData.deduplicateFactsType is not None:
|
|
464
|
+
deduplicatedFacts = frozenset(ValidateDuplicateFacts.getDeduplicatedFacts(modelXbrl, pluginData.deduplicateFactsType))
|
|
465
|
+
duplicateFacts = frozenset(f for f in modelXbrl.facts if f not in deduplicatedFacts)
|
|
466
|
+
if duplicateFacts:
|
|
467
|
+
for fact in duplicateFacts:
|
|
468
|
+
ValidateDuplicateFacts.logDeduplicatedFact(modelXbrl, fact)
|
|
469
|
+
factsToSave = [f for f in factsToSave if f not in duplicateFacts]
|
|
470
|
+
|
|
449
471
|
if isJSON:
|
|
450
472
|
# save JSON
|
|
451
473
|
oimReport["facts"] = oimFacts = {}
|
|
@@ -465,7 +487,7 @@ def saveLoadableOIM(
|
|
|
465
487
|
if fact.modelTupleFacts:
|
|
466
488
|
saveJsonFacts(fact.modelTupleFacts, oimFacts)
|
|
467
489
|
|
|
468
|
-
saveJsonFacts(
|
|
490
|
+
saveJsonFacts(factsToSave, oimFacts)
|
|
469
491
|
|
|
470
492
|
# add footnotes as pseudo facts
|
|
471
493
|
for ftObj in footnoteFacts:
|
|
@@ -651,7 +673,7 @@ def saveLoadableOIM(
|
|
|
651
673
|
_writerow(aspectCols(fact))
|
|
652
674
|
saveCSVfacts(fact.modelTupleFacts)
|
|
653
675
|
|
|
654
|
-
saveCSVfacts(
|
|
676
|
+
saveCSVfacts(factsToSave)
|
|
655
677
|
_close()
|
|
656
678
|
|
|
657
679
|
# save footnotes
|
|
@@ -747,6 +769,7 @@ def saveOimFiles(
|
|
|
747
769
|
|
|
748
770
|
@dataclass
|
|
749
771
|
class SaveLoadableOIMPluginData(PluginData):
|
|
772
|
+
deduplicateFactsType: ValidateDuplicateFacts.DeduplicationType | None
|
|
750
773
|
saveTestcaseOimFileSuffix: str | None
|
|
751
774
|
|
|
752
775
|
|
|
@@ -775,6 +798,12 @@ class SaveLoadableOIMPlugin(PluginHooks):
|
|
|
775
798
|
dest="saveTestcaseOimFileSuffix",
|
|
776
799
|
help=_("Save Testcase Variation OIM file (argument file suffix and type, such as -savedOim.csv"),
|
|
777
800
|
)
|
|
801
|
+
parser.add_option(
|
|
802
|
+
"--deduplicateOimFacts",
|
|
803
|
+
action="store",
|
|
804
|
+
choices=[a.value for a in ValidateDuplicateFacts.DeduplicationType],
|
|
805
|
+
dest="deduplicateOimFacts",
|
|
806
|
+
help=_("Remove duplicate facts when saving the OIM instance"))
|
|
778
807
|
|
|
779
808
|
@staticmethod
|
|
780
809
|
def cntlrCmdLineUtilityRun(
|
|
@@ -783,8 +812,12 @@ class SaveLoadableOIMPlugin(PluginHooks):
|
|
|
783
812
|
*args: Any,
|
|
784
813
|
**kwargs: Any,
|
|
785
814
|
) -> None:
|
|
815
|
+
deduplicateOimFacts = cast(Optional[str], getattr(options, "deduplicateOimFacts", None))
|
|
786
816
|
saveTestcaseOimFileSuffix = cast(Optional[str], getattr(options, "saveTestcaseOimFileSuffix", None))
|
|
787
|
-
|
|
817
|
+
deduplicateFactsType = None
|
|
818
|
+
if deduplicateOimFacts is not None:
|
|
819
|
+
deduplicateFactsType = ValidateDuplicateFacts.DeduplicationType(deduplicateOimFacts)
|
|
820
|
+
pluginData = SaveLoadableOIMPluginData(PLUGIN_NAME, deduplicateFactsType, saveTestcaseOimFileSuffix)
|
|
788
821
|
cntlr.setPluginData(pluginData)
|
|
789
822
|
|
|
790
823
|
@staticmethod
|
|
@@ -789,7 +789,7 @@ def validateXbrlFinally(val: ValidateXbrl, *args: Any, **kwargs: Any) -> None:
|
|
|
789
789
|
elif arcrole in (hc_all, domainMember, dimensionDomain):
|
|
790
790
|
# all primary items
|
|
791
791
|
if fr is not None and not fr.isAbstract and rel.isUsable and fr not in conceptsUsed and isExtension(val, rel) and not fr.type.isDomainItemType:
|
|
792
|
-
unreportedLbElts.add(
|
|
792
|
+
unreportedLbElts.add(fr)
|
|
793
793
|
if to is not None and not to.isAbstract and rel.isUsable and to not in conceptsUsed and isExtension(val, rel) and not to.type.isDomainItemType:
|
|
794
794
|
unreportedLbElts.add(to)
|
|
795
795
|
reportedEltsNotInLb.discard(fr)
|
|
@@ -872,7 +872,7 @@ def validateXbrlFinally(val: ValidateXbrl, *args: Any, **kwargs: Any) -> None:
|
|
|
872
872
|
elif arcrole in (hc_all, domainMember, dimensionDomain):
|
|
873
873
|
# all primary items
|
|
874
874
|
if fr is not None and not fr.isAbstract and rel.isUsable and fr not in conceptsUsed and isExtension(val, rel) and not fr.type.isDomainItemType:
|
|
875
|
-
unreportedLbLocs.add(rel.
|
|
875
|
+
unreportedLbLocs.add(rel.fromLocator)
|
|
876
876
|
if to is not None and not to.isAbstract and rel.isUsable and to not in conceptsUsed and isExtension(val, rel) and not to.type.isDomainItemType:
|
|
877
877
|
unreportedLbLocs.add(rel.toLocator)
|
|
878
878
|
reportedEltsNotInLb.discard(fr)
|
|
@@ -44,11 +44,11 @@ def resolveTableStructure(view, viewTblELR):
|
|
|
44
44
|
|
|
45
45
|
# find an ELR for this table object
|
|
46
46
|
defnMdlTable = viewTblELR
|
|
47
|
-
|
|
47
|
+
strctMdlTableSet = StrctMdlTableSet(defnMdlTable)
|
|
48
48
|
for rel in view.modelXbrl.relationshipSet((XbrlConst.tableBreakdown, XbrlConst.tableBreakdownMMDD)).fromModelObject(defnMdlTable):
|
|
49
49
|
# find relationships in table's linkrole
|
|
50
50
|
view.defnSubtreeRelSet = view.modelXbrl.relationshipSet((XbrlConst.tableBreakdownTree, XbrlConst.tableBreakdownTreeMMDD), rel.linkrole)
|
|
51
|
-
return resolveTableAxesStructure(view,
|
|
51
|
+
return resolveTableAxesStructure(view, strctMdlTableSet,
|
|
52
52
|
view.modelXbrl.relationshipSet((XbrlConst.tableBreakdown, XbrlConst.tableBreakdownMMDD), rel.linkrole))
|
|
53
53
|
# no relationships from table found
|
|
54
54
|
return None
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
arelle/Aspect.py,sha256=Pn9I91D1os1RTVj6htuxTfRzVMhmVDtrbKvV_zy9xMI,5470
|
|
2
2
|
arelle/BetaFeatures.py,sha256=T_tPac-FiozHyYLCemt0RoHJ1JahUE71L-0tHmIRKpE,858
|
|
3
3
|
arelle/Cntlr.py,sha256=sf5Xe19t5E0wKzhdlXl1p5r6gMtCmPhYAi8RVY0jz7Y,30449
|
|
4
|
-
arelle/CntlrCmdLine.py,sha256=
|
|
4
|
+
arelle/CntlrCmdLine.py,sha256=XsSQBeqxlV9bODedGkmUz4nHbPHAAaxo42KdpmpsBj0,94214
|
|
5
5
|
arelle/CntlrComServer.py,sha256=h1KPf31uMbErpxTZn_iklDqUMGFgQnjZkFkFjd8gtLQ,1888
|
|
6
6
|
arelle/CntlrProfiler.py,sha256=2VQJudiUhxryVypxjODx2ccP1-n60icTiWs5lSEokhQ,972
|
|
7
7
|
arelle/CntlrQuickBooks.py,sha256=BMqd5nkNQOZyNFPefkTeWUUDCYNS6BQavaG8k1Lepu4,31543
|
|
8
8
|
arelle/CntlrWebMain.py,sha256=eOzqrp0XA3TrOu7m6Arcvnmdxt7-7zQ8xyaLs-dpDHg,51028
|
|
9
|
-
arelle/CntlrWinMain.py,sha256=
|
|
9
|
+
arelle/CntlrWinMain.py,sha256=0Ctbf7Tk0Y0pjJhLlZecwL46FUmdjw3d1joto21DwOA,96174
|
|
10
10
|
arelle/CntlrWinTooltip.py,sha256=6MzoAIfkYnNu_bl_je8n0adhwmKxAIcymkg9Tij9Z4M,7951
|
|
11
11
|
arelle/DialogAbout.py,sha256=XXzMV0fO4BQ3-l1Puirzmn7EZEdmgJg7JNYdJm1FueM,1987
|
|
12
12
|
arelle/DialogArcroleGroup.py,sha256=r81OT3LFmMkoROpFenk97oVEyQhibKZ1QgDHvMsyCl0,7547
|
|
@@ -38,7 +38,7 @@ arelle/ModelDocument.py,sha256=bP8WbSmBlk3ZxgrQxIfXMfU3Xjo7kgTtWZzxnCZvI88,12921
|
|
|
38
38
|
arelle/ModelDtsObject.py,sha256=JXPRiFOsbB5tZjEDc6rECuUtXMbF4oxfnwrQvKo-i5U,88656
|
|
39
39
|
arelle/ModelFormulaObject.py,sha256=beUSxEFm7aoa9iimmvXLYCHdizAtOmhDqk6wmvbc9Zg,122537
|
|
40
40
|
arelle/ModelInstanceObject.py,sha256=pAcwQBr85_fQCGT18JSOGGwzAZ3J-oWIU9sj9UUXLOk,73928
|
|
41
|
-
arelle/ModelManager.py,sha256=
|
|
41
|
+
arelle/ModelManager.py,sha256=QUNcD2LC_YyyGFU8bFTSuzIGI1qpOK55KBlQ697Ep1I,11075
|
|
42
42
|
arelle/ModelObject.py,sha256=Rttkhv-PtfneZyDYsG5FDh98BzT97ameTmwNdqFaOv0,18657
|
|
43
43
|
arelle/ModelObjectFactory.py,sha256=XuNF4Re3p00tODCdyspfar_DNCXfARqCaLEkntgAZ0g,8750
|
|
44
44
|
arelle/ModelRelationshipSet.py,sha256=_1T3NAS0IRgK8IWFe7nh-qxXZ7htA80i_dueyU8JYaU,24654
|
|
@@ -46,7 +46,7 @@ arelle/ModelRenderingObject.py,sha256=iPhSUlSBG-FLzAfIdUW06UZDgTCaZJ4K2mxvAtSe2B
|
|
|
46
46
|
arelle/ModelRssItem.py,sha256=GzFkmluOlFsVcrxn9HAyOAcuE7rcHUOGkp4Q6F2IlT8,7713
|
|
47
47
|
arelle/ModelRssObject.py,sha256=xjuwyJ8pU5sQmNPJFQakDEEnujZg2bMCTaj3zVezHL8,992
|
|
48
48
|
arelle/ModelTestcaseObject.py,sha256=qWSphg4BX8HMcmEt_IJ8pS_uU1G7XeIldTshEpAi0GY,21873
|
|
49
|
-
arelle/ModelValue.py,sha256=
|
|
49
|
+
arelle/ModelValue.py,sha256=6Vko4aytXg2Ajv7rI6houQb-ZX39-tcjQ4N90ZxZvE8,39430
|
|
50
50
|
arelle/ModelVersObject.py,sha256=cPD1IzhkCfuV1eMgVFWes88DH_6WkUj5kj7sgGF2M0I,26062
|
|
51
51
|
arelle/ModelVersReport.py,sha256=bXEA9K3qkH57aABn5l-m3CTY0FAcF1yX6O4fo-URjl8,73326
|
|
52
52
|
arelle/ModelXbrl.py,sha256=7rz4rxIGopwRDQTD12P0sdqzvPPoMhGgkg5qkMD6TDQ,72109
|
|
@@ -56,7 +56,7 @@ arelle/PluginUtils.py,sha256=0vFQ29wVVpU0cTY3YOBL6FhNQhhCTwShBH4qTJGLnvc,2426
|
|
|
56
56
|
arelle/PrototypeDtsObject.py,sha256=0lf60VcXR_isx57hBPrc7vEMkFpYkVuK4JVBSmopzkQ,7989
|
|
57
57
|
arelle/PrototypeInstanceObject.py,sha256=CXUoDllhDqpMvSQjqIYi1Ywp-J8fLhQRV9wVD2YXgVo,13204
|
|
58
58
|
arelle/PythonUtil.py,sha256=pP59gx2-z3dKLesUqiDVZmbhCOS1kpQzowsQ9ShJi-0,7947
|
|
59
|
-
arelle/RuntimeOptions.py,sha256=
|
|
59
|
+
arelle/RuntimeOptions.py,sha256=89pSw3zFhjHzn75RaHAl4-iPXL8awTZny-frozn9EHQ,8718
|
|
60
60
|
arelle/SocketUtils.py,sha256=1wa2sA_QhM8F1klHFq90V1AgO1-hY9pJm0554FiF7Lc,677
|
|
61
61
|
arelle/SystemInfo.py,sha256=6330pNedRkAPlEKl-ZdaZHiGuucEGZMI-Jrdy7B1rrU,2454
|
|
62
62
|
arelle/TableStructure.py,sha256=PABOHJiTa56cHyF9qRLD7TohmCHyDTrGEltW8toP_rk,29409
|
|
@@ -73,7 +73,7 @@ arelle/ValidateUtr.py,sha256=oxOPrOa1XEzBay4miXvx6eRLTnVFYUIJC9ueWUk4EkI,13633
|
|
|
73
73
|
arelle/ValidateVersReport.py,sha256=RMe7GlcyZV0HoVFHL0qOGrKm4et-6yPq5dmikkhnvoU,43196
|
|
74
74
|
arelle/ValidateXbrl.py,sha256=kBiY_q9QmORwC8VxGpRq9mfufknt08nEAeSgNh1ov-M,78005
|
|
75
75
|
arelle/ValidateXbrlCalcs.py,sha256=vx1LYbu2l6wY88O9vyaThK5gOG59R9ggHX3FapbN3XA,44308
|
|
76
|
-
arelle/ValidateXbrlDTS.py,sha256=
|
|
76
|
+
arelle/ValidateXbrlDTS.py,sha256=yxvpTpImEbrQuLJ2aJf38FjA-OEznpWWdsDK0GtLXIU,104003
|
|
77
77
|
arelle/ValidateXbrlDimensions.py,sha256=Qv7_CI65SiUcpgsnEc86XuMjKz81-170wE5dmZqnvHc,38373
|
|
78
78
|
arelle/Version.py,sha256=Cdl7IhBHOIdfgWtBVAkeG4cXby84g21NOjkECsgaflM,1067
|
|
79
79
|
arelle/ViewFile.py,sha256=Bvh50RAHDEauAmF0KPHWAZocMyA0UCduJ46e0wbSnPE,19286
|
|
@@ -83,8 +83,8 @@ arelle/ViewFileFactList.py,sha256=AVYoDJnhUoIkX7fT2D-bOrKP5g1JAwVnmSr4FYhT4iI,71
|
|
|
83
83
|
arelle/ViewFileFactTable.py,sha256=I3U6XomCHE5bnbUN_WMq80LyYnPz0GRgYdRDm8Pu3tg,17013
|
|
84
84
|
arelle/ViewFileFormulae.py,sha256=753p3pAZsoxx6-3b_xR_CDFReeMBgBZOCV_TIO0FuJE,4740
|
|
85
85
|
arelle/ViewFileRelationshipSet.py,sha256=ZNxRQc57FMM1erJk-VcuVMeScMxr7zev17Rb3ng0JK0,16764
|
|
86
|
-
arelle/ViewFileRenderedGrid.py,sha256=
|
|
87
|
-
arelle/ViewFileRenderedLayout.py,sha256=
|
|
86
|
+
arelle/ViewFileRenderedGrid.py,sha256=I0Q6tyhbu1vcZvWiigAGrPK2bHv_ixsZvLr3merYPJo,14112
|
|
87
|
+
arelle/ViewFileRenderedLayout.py,sha256=aCTpOMBUIKYE4Xu1OFPoo_NTqp1NqefpXze6qWcDKw8,12170
|
|
88
88
|
arelle/ViewFileRenderedStructure.py,sha256=VemGa9HlVHvazPD3-yOrtDWTggNBkHkNtzXHtLUqngA,6192
|
|
89
89
|
arelle/ViewFileRoleTypes.py,sha256=4rk7D0sd5TP6o_WNm2wkBxB2OeltUrk6InfJHPLwLDQ,2024
|
|
90
90
|
arelle/ViewFileRssFeed.py,sha256=7ATWTC42QrCPTZxTK8-MH0-mDOGg0GUms7AWdzJfPKc,2726
|
|
@@ -103,7 +103,7 @@ arelle/ViewWinList.py,sha256=dz7qip9DpvVi96j71MZQoQpaVguO4FRka-_TOnsJtaE,4318
|
|
|
103
103
|
arelle/ViewWinPane.py,sha256=ZTz1fL3-QXZLAIMjqAjGoe9IEMVG7s9AzFYamV2PTco,2783
|
|
104
104
|
arelle/ViewWinProperties.py,sha256=FutWixP6g-_riNsnCxef6dej_kNqH_E2F3anse60aV4,2403
|
|
105
105
|
arelle/ViewWinRelationshipSet.py,sha256=7XAmQ0o9orMDFB0Ew_Ph6FYHtsvss2c6drIQajsOnXk,25577
|
|
106
|
-
arelle/ViewWinRenderedGrid.py,sha256=
|
|
106
|
+
arelle/ViewWinRenderedGrid.py,sha256=OFFypVdoPke6FVa0fPC0TaFAC2nBOIsJOFF62xNsTnQ,84625
|
|
107
107
|
arelle/ViewWinRoleTypes.py,sha256=hc1pM5Q_LYOxDxMJTvG1O4_pQ0Uni9kpZ6hPuxKNs9w,4794
|
|
108
108
|
arelle/ViewWinRssFeed.py,sha256=htgZKAxA3ivuE6p-jvtU2HIx78LAtfAkO2Q-KtGYHIk,6057
|
|
109
109
|
arelle/ViewWinTests.py,sha256=1RNerlovLzyvemNPFjraEVmpVWcWiw_DQ5LxVZm0R4M,9414
|
|
@@ -117,13 +117,13 @@ arelle/WebCache.py,sha256=_GDLhkEf1fxe0nTdO5eCKdNcB1f3Dfv2E6H5PPjNeX8,44733
|
|
|
117
117
|
arelle/XbrlConst.py,sha256=YDvnf0gQ3IY5v07d8wxAHTxDmvcHIpl2mSMZeTgvKmk,56695
|
|
118
118
|
arelle/XbrlUtil.py,sha256=s2Vmrh-sZI5TeuqsziKignOc3ao-uUgnCNoelP4dDj0,9212
|
|
119
119
|
arelle/XhtmlValidate.py,sha256=0gtm7N-kXK0RB5o3c1AQXjfFuRp1w2fKZZAeyruNANw,5727
|
|
120
|
-
arelle/XmlUtil.py,sha256=
|
|
120
|
+
arelle/XmlUtil.py,sha256=1VToOOylF8kbEorEdZLThmq35j9bmuF_DS2q9NthnHU,58774
|
|
121
121
|
arelle/XmlValidate.py,sha256=TL72yUQA0PqdcFgw7rW8uxUWw6i1pN7q6V42Uk6gMYY,45857
|
|
122
122
|
arelle/XmlValidateConst.py,sha256=U_wN0Q-nWKwf6dKJtcu_83FXPn9c6P8JjzGA5b0w7P0,338
|
|
123
123
|
arelle/XmlValidateParticles.py,sha256=Mn6vhFl0ZKC_vag1mBwn1rH_x2jmlusJYqOOuxFPO2k,9231
|
|
124
124
|
arelle/XmlValidateSchema.py,sha256=6frtZOc1Yrx_5yYF6V6oHbScnglWrVbWr6xW4EHtLQI,7428
|
|
125
125
|
arelle/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
126
|
-
arelle/_version.py,sha256=
|
|
126
|
+
arelle/_version.py,sha256=nyprLxQLl4J8OXRCVQ_v7F0qoM1HHVnAlbQEmqspAag,515
|
|
127
127
|
arelle/typing.py,sha256=Ct5lrNKRow_o9CraMEXNza8nFsJ_iGIKoUeGfPs2dxI,1084
|
|
128
128
|
arelle/api/Session.py,sha256=Vd09RAutWX7mxHSsrW7Bl8CsE1UzXpQpAJsZb55mqng,6188
|
|
129
129
|
arelle/archive/CustomLogger.py,sha256=v_JXOCQLDZcfaFWzxC9FRcEf9tQi4rCI4Sx7jCuAVQI,1231
|
|
@@ -323,7 +323,7 @@ arelle/plugin/saveCHComponentFile.py,sha256=phW-n96P0BWONLqX3wBcuNcDa_IQ8QVfFWKL
|
|
|
323
323
|
arelle/plugin/saveDTS.py,sha256=D8hfFiM9Gc9LE7ZV0-pDvOHeU7Y5ebOzZx_nXzoZrl8,3216
|
|
324
324
|
arelle/plugin/saveHtmlEBAtables.py,sha256=OITN4ftI_atUO5NvrDJDKUc0CAk67GY68Jl16xDBXiI,10961
|
|
325
325
|
arelle/plugin/saveLoadableExcel.py,sha256=ZPYB6injFabav0dRzgS7adCFzfHkwtftjl3PfBjijuU,20539
|
|
326
|
-
arelle/plugin/saveLoadableOIM.py,sha256=
|
|
326
|
+
arelle/plugin/saveLoadableOIM.py,sha256=onT61QRygFCMGS7xTZHJz9WSo1V5PyqKQRtoTBf7GDE,38180
|
|
327
327
|
arelle/plugin/saveSKOS.py,sha256=7Z1Qedf83zMo9EbigKkxNpiMjzkTYQvLEnwWMObLc1Y,12465
|
|
328
328
|
arelle/plugin/saveSampleInstance.py,sha256=w66Nd4He8yIK4Il_M9qnelpeUJ_6cBBe5q01DanOxEA,23823
|
|
329
329
|
arelle/plugin/streamingExtensions.py,sha256=gDt3TfkHcDHqnP8jnBWmC3j5i0u53lgUOSKxHJU8HnI,47646
|
|
@@ -366,11 +366,11 @@ arelle/plugin/validate/ESEF/Util.py,sha256=pNwtMG2pIQsGpuc0X4oopXdqnIu9HI16Ado2D
|
|
|
366
366
|
arelle/plugin/validate/ESEF/__init__.py,sha256=LL7uYOcGPHgjwTlcfW2oWMqWiqrZ5yABzcKkJZFrZis,20391
|
|
367
367
|
arelle/plugin/validate/ESEF/ESEF_2021/DTS.py,sha256=6Za7BANwwc_egxLCgbgWzwUGOXZv9IF1I7JCkDNt2Tw,26277
|
|
368
368
|
arelle/plugin/validate/ESEF/ESEF_2021/Image.py,sha256=4bnhuy5viBU0viPjb4FhcRRjVVKlNdnKLFdSGg3sZvs,4871
|
|
369
|
-
arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py,sha256=
|
|
369
|
+
arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py,sha256=r6U0GQNyMmwSeWESO7Po--28PA6iacgQMaQVSm7uh1M,62811
|
|
370
370
|
arelle/plugin/validate/ESEF/ESEF_2021/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
371
371
|
arelle/plugin/validate/ESEF/ESEF_Current/DTS.py,sha256=epp-PBh1NJzQqgxUE6C468HmoDc2w3j54rMwfiOAry4,29334
|
|
372
372
|
arelle/plugin/validate/ESEF/ESEF_Current/Image.py,sha256=w36sCTy8QbsuKABjkK6PTWce2A4zFN_rMnEM2wi5WEc,11364
|
|
373
|
-
arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py,sha256=
|
|
373
|
+
arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py,sha256=0t9FJ98M4LAQ2yYZqTUgjF2KKQWFDpRoj7EhZezpyqI,73082
|
|
374
374
|
arelle/plugin/validate/ESEF/ESEF_Current/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
375
375
|
arelle/plugin/validate/ESEF/resources/authority-validations.json,sha256=JriLZ45KmUYlQiPbXJCAahobqdrst64Ay77bofZhB5Q,14940
|
|
376
376
|
arelle/plugin/validate/ESEF/resources/config.xml,sha256=t3STU_-QYM7Ay8YwZRPapnohiWVWhjfr4L2Rjx9xN9U,3902
|
|
@@ -431,7 +431,7 @@ arelle/plugin/xbrlDB/sql/semantic/xbrlSemanticPostgresDB.ddl,sha256=DYBE4m2gSp-2
|
|
|
431
431
|
arelle/plugin/xbrlDB/sql/semantic/xbrlSemanticSQLiteDB.ddl,sha256=TRb4zLoXUGKkBU1ZR5KCpMLBpujtNiL_WDdnv4DfBL0,726301
|
|
432
432
|
arelle/rendering/RenderingEvaluator.py,sha256=suQhQsx5KD1QJMGxIiPXGbUOKQMTwg1oSSJlgl8J8kk,17781
|
|
433
433
|
arelle/rendering/RenderingLayout.py,sha256=dIpR0hGyIvYR-Qj61wSb0YkgJdHbtqtlAtFGEbb65JY,31082
|
|
434
|
-
arelle/rendering/RenderingResolution.py,sha256=
|
|
434
|
+
arelle/rendering/RenderingResolution.py,sha256=W21PdF7UTmL546Hbtycaf2semGWOPNrpETDeQR9elnA,54553
|
|
435
435
|
arelle/resources/cache/http/www.eurofiling.info/eu/fr/xbrl/ext/filing-indicators.xsd,sha256=BfDzYGRz5zofzjnvVP_ZdTVtddxKdsrYfjZ3dK_hJIQ,1243
|
|
436
436
|
arelle/resources/cache/http/www.w3.org/2001/XMLSchema.xsd,sha256=52ehWcF5vW5NwrrCpjpi9Qy9An7BnWtcyescLzPgyy4,87677
|
|
437
437
|
arelle/resources/cache/http/www.w3.org/2001/xml.xsd,sha256=YZYPsxMeOAIsqtU2Di8zozgleKs8gM1YvXQyDt5hsgw,8836
|
|
@@ -741,30 +741,30 @@ tests/integration_tests/validation/download_assets.py,sha256=muHklbrvYEbxqqAM8mU
|
|
|
741
741
|
tests/integration_tests/validation/run_conformance_suites.py,sha256=pDtBUEfT-pggxKEN2cg3vk0_Cko6wgV3x-6cX7y3Y3M,8206
|
|
742
742
|
tests/integration_tests/validation/test_conformance_suites.py,sha256=VdwY0QtV6g00M9bv1XNs4qBTwxPxCh5-z4XoDdEhgeM,711
|
|
743
743
|
tests/integration_tests/validation/validation_util.py,sha256=W5_NpjlqVKlmV8LGgzQLIFtmgEFPO4YgSOTymQX_rns,21541
|
|
744
|
-
tests/integration_tests/validation/conformance_suite_configurations/cipc_current.py,sha256=
|
|
745
|
-
tests/integration_tests/validation/conformance_suite_configurations/dba_current.py,sha256=
|
|
746
|
-
tests/integration_tests/validation/conformance_suite_configurations/dba_multi_current.py,sha256=
|
|
744
|
+
tests/integration_tests/validation/conformance_suite_configurations/cipc_current.py,sha256=oLXe3xIsEZLz3cv1cDdMQIuS_NgyI9Uimc9hy0NMWqg,642
|
|
745
|
+
tests/integration_tests/validation/conformance_suite_configurations/dba_current.py,sha256=j-7jCpzbGXbOzG8HGEyS0ciCYSPZzZLV44VQGhP3Hmc,875
|
|
746
|
+
tests/integration_tests/validation/conformance_suite_configurations/dba_multi_current.py,sha256=ICkP18Wu7aTDfszfYlrfVnBj9oe7ppXR-8wxQqCPqW0,837
|
|
747
747
|
tests/integration_tests/validation/conformance_suite_configurations/efm_current.py,sha256=LoAuqV3uMiQSfgQ34c_T70ph3YT7py5nu10podbIFRM,1322
|
|
748
748
|
tests/integration_tests/validation/conformance_suite_configurations/efm_reg_dqc.py,sha256=HiT8OcRAOVKLsl95Y91L66FeOsIMMMAQCs-DLMG-Lb0,739
|
|
749
749
|
tests/integration_tests/validation/conformance_suite_configurations/efm_reg_pragmatic.py,sha256=U6dew0sIibjZe4r6na912qyIVAjxljh2HDix-8AwvhM,727
|
|
750
|
-
tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2021.py,sha256=
|
|
751
|
-
tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2022.py,sha256=
|
|
752
|
-
tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2023.py,sha256=
|
|
753
|
-
tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2024.py,sha256=
|
|
754
|
-
tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2021.py,sha256=
|
|
755
|
-
tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2022.py,sha256=
|
|
756
|
-
tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2023.py,sha256=
|
|
757
|
-
tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2024.py,sha256=
|
|
758
|
-
tests/integration_tests/validation/conformance_suite_configurations/hmrc_current.py,sha256=
|
|
759
|
-
tests/integration_tests/validation/conformance_suite_configurations/kvk_nt16.py,sha256=
|
|
760
|
-
tests/integration_tests/validation/conformance_suite_configurations/kvk_nt17.py,sha256=
|
|
761
|
-
tests/integration_tests/validation/conformance_suite_configurations/kvk_nt18.py,sha256=
|
|
762
|
-
tests/integration_tests/validation/conformance_suite_configurations/kvk_nt19.py,sha256=
|
|
763
|
-
tests/integration_tests/validation/conformance_suite_configurations/nl_nt16.py,sha256=
|
|
764
|
-
tests/integration_tests/validation/conformance_suite_configurations/nl_nt17.py,sha256=
|
|
765
|
-
tests/integration_tests/validation/conformance_suite_configurations/nl_nt18.py,sha256=
|
|
766
|
-
tests/integration_tests/validation/conformance_suite_configurations/nl_nt19.py,sha256=
|
|
767
|
-
tests/integration_tests/validation/conformance_suite_configurations/ros_current.py,sha256=
|
|
750
|
+
tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2021.py,sha256=KpXpm6kMYAp94K-J7-GZS47iRVE9Kr5cfxPniFFSI3A,1146
|
|
751
|
+
tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2022.py,sha256=tllelZOW7R5udOhEtjnQGAVy0MxAAM03OY_cC4pstgY,1575
|
|
752
|
+
tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2023.py,sha256=Imhckmr7vui2xrWdsWaengly-5e2CUeoqh2ZDTscek8,1833
|
|
753
|
+
tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2024.py,sha256=Eu3I5Tn1ow7fB4y9KMgSe9q4W5NBfME6pHzBBmEwgqM,1610
|
|
754
|
+
tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2021.py,sha256=535hJ9CEPJPT-ciHumkii6xlJXwsV1KfL_Q9a4fjxcc,971
|
|
755
|
+
tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2022.py,sha256=fr5GIUrbKB4_f7YIkSQz9hbpqFWuQyLmo4awtvODfU4,948
|
|
756
|
+
tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2023.py,sha256=hOpfcMcnu_plJB-mpqyTywAncW_iPJGlZsn5hfD9sk0,920
|
|
757
|
+
tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2024.py,sha256=4x8r-B6f4W2J_KFGKi2Q923TxdJxKv6_YxQS8I6Uo1k,966
|
|
758
|
+
tests/integration_tests/validation/conformance_suite_configurations/hmrc_current.py,sha256=0a-RIuA4xoLXyxenXt740wzhV-0JX2aOrlSPF9qQgE0,1896
|
|
759
|
+
tests/integration_tests/validation/conformance_suite_configurations/kvk_nt16.py,sha256=fIGmQ_7yJAnFvA-Si6dGOpdUlJbi8FQ-ODWoAC09SgI,1525
|
|
760
|
+
tests/integration_tests/validation/conformance_suite_configurations/kvk_nt17.py,sha256=lmEZonthFm0YKFmp1dwXtdJ2T7txUeSpL4mbAo8fl4Y,1292
|
|
761
|
+
tests/integration_tests/validation/conformance_suite_configurations/kvk_nt18.py,sha256=EG2RQVkvFENhzUF3fl3QvDnH7ZPYS1n1Fo8bhfmSczM,1205
|
|
762
|
+
tests/integration_tests/validation/conformance_suite_configurations/kvk_nt19.py,sha256=FAzf9RhRmn_8yowpplJho2zEspX9FxJiVq8SjZT3Dsc,1199
|
|
763
|
+
tests/integration_tests/validation/conformance_suite_configurations/nl_nt16.py,sha256=O_LFVBZPkjxmbrU7_C7VTLtrdoCUx2bYXOXw6_MlRtQ,846
|
|
764
|
+
tests/integration_tests/validation/conformance_suite_configurations/nl_nt17.py,sha256=aTN3Ez6lPsZsuypHZP84DneOtYxUZSjUiGypHy6ofHQ,846
|
|
765
|
+
tests/integration_tests/validation/conformance_suite_configurations/nl_nt18.py,sha256=sqHLjrHc95dTu0guTgKkphaKM1zNfKGnN4GKkZDLzeU,845
|
|
766
|
+
tests/integration_tests/validation/conformance_suite_configurations/nl_nt19.py,sha256=_CiNflzz0ItJslvv22CL70yyK3P7hVGYLZ3BIb0y9Ww,844
|
|
767
|
+
tests/integration_tests/validation/conformance_suite_configurations/ros_current.py,sha256=yEt0XHxX6jNpbslQaIeOce07eh3dsdGP-e7ydOiZzog,725
|
|
768
768
|
tests/integration_tests/validation/conformance_suite_configurations/xbrl_2_1.py,sha256=GFPkzqk2lwDgHEUIRAFS9-htMOS0THmjsXT9eJDfiSc,1494
|
|
769
769
|
tests/integration_tests/validation/conformance_suite_configurations/xbrl_calculations_1_1.py,sha256=0XV1FXxFiSk5hcsSaEsT7JVGQ3KXV8FrHNmr-tqo3Zg,816
|
|
770
770
|
tests/integration_tests/validation/conformance_suite_configurations/xbrl_dimensions_1_0.py,sha256=NtliBDgTxKvpC3j75hmJSrcIIkVlA4q_q6OEXf9b28w,1871
|
|
@@ -1553,9 +1553,9 @@ tests/unit_tests/arelle/oim/test_load.py,sha256=NxiUauQwJVfWAHbbpsMHGSU2d3Br8Pki
|
|
|
1553
1553
|
tests/unit_tests/arelle/plugin/test_plugin_imports.py,sha256=bdhIs9frAnFsdGU113yBk09_jis-z43dwUItMFYuSYM,1064
|
|
1554
1554
|
tests/unit_tests/arelle/plugin/validate/ESEF/ESEF_Current/test_validate_css_url.py,sha256=XHABmejQt7RlZ0udh7v42f2Xb2STGk_fSaIaJ9i2xo0,878
|
|
1555
1555
|
tests/unit_tests/arelle/utils/validate/test_decorator.py,sha256=ZS8FqIY1g-2FCbjF4UYm609dwViax6qBMRJSi0vfuhY,2482
|
|
1556
|
-
arelle_release-2.36.
|
|
1557
|
-
arelle_release-2.36.
|
|
1558
|
-
arelle_release-2.36.
|
|
1559
|
-
arelle_release-2.36.
|
|
1560
|
-
arelle_release-2.36.
|
|
1561
|
-
arelle_release-2.36.
|
|
1556
|
+
arelle_release-2.36.31.dist-info/LICENSE.md,sha256=rMbWwFLGzPgLoEjEu8LCmkpWDTqsvfOI-wzLSfeJsis,4107
|
|
1557
|
+
arelle_release-2.36.31.dist-info/METADATA,sha256=dpGpu4tPQ9S6bIglo-0xhUDBAFh5hhNGL6A-MbpERRo,9010
|
|
1558
|
+
arelle_release-2.36.31.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
|
|
1559
|
+
arelle_release-2.36.31.dist-info/entry_points.txt,sha256=Uj5niwfwVsx3vaQ3fYj8hrZ1xpfCJyTUA09tYKWbzpo,111
|
|
1560
|
+
arelle_release-2.36.31.dist-info/top_level.txt,sha256=ZYmYGmhW5Jvo3vJ4iXBZPUI29LvYhntom04w90esJvU,13
|
|
1561
|
+
arelle_release-2.36.31.dist-info/RECORD,,
|
|
@@ -4,6 +4,7 @@ from tests.integration_tests.validation.conformance_suite_config import Conforma
|
|
|
4
4
|
config = ConformanceSuiteConfig(
|
|
5
5
|
args=[
|
|
6
6
|
'--disclosureSystem', 'arl-2022-preview',
|
|
7
|
+
'--baseTaxonomyValidation', 'none',
|
|
7
8
|
],
|
|
8
9
|
assets=[
|
|
9
10
|
ConformanceSuiteAssetConfig.local_conformance_suite(
|
|
@@ -4,6 +4,7 @@ from tests.integration_tests.validation.conformance_suite_config import Conforma
|
|
|
4
4
|
config = ConformanceSuiteConfig(
|
|
5
5
|
args=[
|
|
6
6
|
'--disclosureSystem', 'arl-2024-multi-target-preview',
|
|
7
|
+
'--baseTaxonomyValidation', 'none',
|
|
7
8
|
],
|
|
8
9
|
assets=[
|
|
9
10
|
ConformanceSuiteAssetConfig.local_conformance_suite(
|
|
@@ -10,6 +10,7 @@ from tests.integration_tests.validation.conformance_suite_config import (
|
|
|
10
10
|
config = ConformanceSuiteConfig(
|
|
11
11
|
args=[
|
|
12
12
|
'--disclosureSystem', 'esef-2024',
|
|
13
|
+
'--baseTaxonomyValidation', 'none',
|
|
13
14
|
],
|
|
14
15
|
assets=[
|
|
15
16
|
ConformanceSuiteAssetConfig.conformance_suite(
|
|
@@ -4,6 +4,7 @@ from tests.integration_tests.validation.conformance_suite_config import Conforma
|
|
|
4
4
|
config = ConformanceSuiteConfig(
|
|
5
5
|
args=[
|
|
6
6
|
'--disclosureSystem', 'esef-unconsolidated-2021',
|
|
7
|
+
'--baseTaxonomyValidation', 'none',
|
|
7
8
|
],
|
|
8
9
|
assets=[
|
|
9
10
|
ConformanceSuiteAssetConfig.conformance_suite(
|
|
@@ -4,6 +4,7 @@ from tests.integration_tests.validation.conformance_suite_config import Conforma
|
|
|
4
4
|
config = ConformanceSuiteConfig(
|
|
5
5
|
args=[
|
|
6
6
|
'--disclosureSystem', 'esef-unconsolidated-2022',
|
|
7
|
+
'--baseTaxonomyValidation', 'none',
|
|
7
8
|
],
|
|
8
9
|
assets=[
|
|
9
10
|
ConformanceSuiteAssetConfig.conformance_suite(
|
|
@@ -4,6 +4,7 @@ from tests.integration_tests.validation.conformance_suite_config import Conforma
|
|
|
4
4
|
config = ConformanceSuiteConfig(
|
|
5
5
|
args=[
|
|
6
6
|
'--disclosureSystem', 'esef-unconsolidated-2023',
|
|
7
|
+
'--baseTaxonomyValidation', 'none',
|
|
7
8
|
],
|
|
8
9
|
assets=[
|
|
9
10
|
ConformanceSuiteAssetConfig.conformance_suite(
|
|
@@ -9,6 +9,7 @@ from tests.integration_tests.validation.conformance_suite_config import (
|
|
|
9
9
|
config = ConformanceSuiteConfig(
|
|
10
10
|
args=[
|
|
11
11
|
'--disclosureSystem', 'esef-unconsolidated-2024',
|
|
12
|
+
'--baseTaxonomyValidation', 'none',
|
|
12
13
|
],
|
|
13
14
|
assets=[
|
|
14
15
|
ConformanceSuiteAssetConfig.conformance_suite(
|
|
@@ -6,6 +6,7 @@ from tests.integration_tests.validation.conformance_suite_config import Conforma
|
|
|
6
6
|
config = ConformanceSuiteConfig(
|
|
7
7
|
args=[
|
|
8
8
|
'--disclosureSystem', 'NT16',
|
|
9
|
+
'--baseTaxonomyValidation', 'none',
|
|
9
10
|
],
|
|
10
11
|
assets=[
|
|
11
12
|
ConformanceSuiteAssetConfig.local_conformance_suite(
|
|
@@ -6,6 +6,7 @@ from tests.integration_tests.validation.conformance_suite_config import Conforma
|
|
|
6
6
|
config = ConformanceSuiteConfig(
|
|
7
7
|
args=[
|
|
8
8
|
'--disclosureSystem', 'NT17',
|
|
9
|
+
'--baseTaxonomyValidation', 'none',
|
|
9
10
|
],
|
|
10
11
|
assets=[
|
|
11
12
|
ConformanceSuiteAssetConfig.local_conformance_suite(
|
|
@@ -6,6 +6,7 @@ from tests.integration_tests.validation.conformance_suite_config import Conforma
|
|
|
6
6
|
config = ConformanceSuiteConfig(
|
|
7
7
|
args=[
|
|
8
8
|
'--disclosureSystem', 'NT18',
|
|
9
|
+
'--baseTaxonomyValidation', 'none',
|
|
9
10
|
],
|
|
10
11
|
assets=[
|
|
11
12
|
ConformanceSuiteAssetConfig.local_conformance_suite(
|
|
@@ -6,6 +6,7 @@ from tests.integration_tests.validation.conformance_suite_config import Conforma
|
|
|
6
6
|
config = ConformanceSuiteConfig(
|
|
7
7
|
args=[
|
|
8
8
|
'--disclosureSystem', 'NT19',
|
|
9
|
+
'--baseTaxonomyValidation', 'none',
|
|
9
10
|
],
|
|
10
11
|
assets=[
|
|
11
12
|
ConformanceSuiteAssetConfig.local_conformance_suite(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|