arelle-release 2.37.46__py3-none-any.whl → 2.38.0__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.
- arelle/BetaFeatures.py +0 -21
- arelle/Cntlr.py +15 -8
- arelle/CntlrCmdLine.py +121 -56
- arelle/CntlrWinMain.py +143 -70
- arelle/DialogFind.py +1 -1
- arelle/DialogPluginManager.py +6 -4
- arelle/DisclosureSystem.py +7 -0
- arelle/ErrorManager.py +21 -6
- arelle/FileSource.py +11 -4
- arelle/FunctionIxt.py +16 -11
- arelle/HtmlUtil.py +5 -4
- arelle/LeiUtil.py +63 -43
- arelle/ModelDocument.py +20 -15
- arelle/ModelDtsObject.py +8 -0
- arelle/ModelInstanceObject.py +1 -1
- arelle/ModelObject.py +16 -18
- arelle/ModelObjectFactory.py +35 -17
- arelle/ModelXbrl.py +28 -11
- arelle/PluginManager.py +130 -105
- arelle/RuntimeOptions.py +1 -0
- arelle/UrlUtil.py +14 -0
- arelle/Validate.py +17 -12
- arelle/ValidateDuplicateFacts.py +3 -1
- arelle/ValidateFileSource.py +38 -0
- arelle/ValidateFilingText.py +3 -3
- arelle/ValidateXbrl.py +5 -2
- arelle/ValidateXbrlCalcs.py +210 -186
- arelle/ValidateXbrlDTS.py +1 -1
- arelle/ViewFile.py +1 -0
- arelle/ViewFileFactTable.py +2 -2
- arelle/ViewWinDTS.py +4 -1
- arelle/WebCache.py +28 -24
- arelle/XbrlConst.py +22 -0
- arelle/XmlUtil.py +16 -21
- arelle/XmlValidate.py +6 -9
- arelle/_version.py +16 -3
- arelle/api/Session.py +11 -2
- arelle/config/disclosuresystems.xsd +2 -0
- arelle/config/rosettaEntitlements.plist +8 -0
- arelle/conformance/CSVTestcaseLoader.py +1 -1
- arelle/formula/XPathContext.py +3 -3
- arelle/logging/formatters/LogFormatter.py +3 -1
- arelle/packages/report/ReportPackage.py +26 -13
- arelle/packages/report/ReportPackageConst.py +0 -1
- arelle/plugin/inlineXbrlDocumentSet.py +19 -5
- arelle/plugin/validate/DBA/DisclosureSystems.py +19 -1
- arelle/plugin/validate/DBA/PluginValidationDataExtension.py +2 -4
- arelle/plugin/validate/DBA/ValidationPluginExtension.py +2 -1
- arelle/plugin/validate/DBA/resources/config.xml +5 -0
- arelle/plugin/validate/DBA/rules/__init__.py +2 -2
- arelle/plugin/validate/DBA/rules/fr.py +19 -2
- arelle/plugin/validate/DBA/rules/tc.py +2 -0
- arelle/plugin/validate/DBA/rules/th.py +6 -0
- arelle/plugin/validate/DBA/rules/tm.py +18 -5
- arelle/plugin/validate/DBA/rules/tr.py +11 -5
- arelle/plugin/validate/EDINET/Constants.py +193 -9
- arelle/plugin/validate/EDINET/ContextRequirement.py +58 -0
- arelle/plugin/validate/EDINET/ControllerPluginData.py +220 -1
- arelle/plugin/validate/EDINET/CoverItemRequirements.py +42 -0
- arelle/plugin/validate/EDINET/DeiRequirements.py +118 -0
- arelle/plugin/validate/EDINET/FilingFormat.py +275 -0
- arelle/plugin/validate/EDINET/FormType.py +134 -0
- arelle/plugin/validate/EDINET/ManifestInstance.py +72 -5
- arelle/plugin/validate/EDINET/NamespaceConfig.py +50 -0
- arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +493 -132
- arelle/plugin/validate/EDINET/{InstanceType.py → ReportFolderType.py} +72 -15
- arelle/plugin/validate/EDINET/Statement.py +139 -0
- arelle/plugin/validate/EDINET/TableOfContentsBuilder.py +595 -0
- arelle/plugin/validate/EDINET/UploadContents.py +48 -0
- arelle/plugin/validate/EDINET/ValidationPluginExtension.py +20 -2
- arelle/plugin/validate/EDINET/__init__.py +31 -6
- arelle/plugin/validate/EDINET/resources/config.xml +8 -1
- arelle/plugin/validate/EDINET/resources/cover-item-requirements.json +793 -0
- arelle/plugin/validate/EDINET/resources/dei-requirements.csv +27 -0
- arelle/plugin/validate/EDINET/resources/edinet-taxonomies.xml +2 -0
- arelle/plugin/validate/EDINET/rules/contexts.py +375 -14
- arelle/plugin/validate/EDINET/rules/edinet.py +1934 -45
- arelle/plugin/validate/EDINET/rules/frta.py +122 -3
- arelle/plugin/validate/EDINET/rules/gfm.py +1907 -11
- arelle/plugin/validate/EDINET/rules/upload.py +989 -141
- arelle/plugin/validate/ESEF/Const.py +3 -1
- arelle/plugin/validate/ESEF/ESEF_2021/DTS.py +5 -0
- arelle/plugin/validate/ESEF/ESEF_2021/Image.py +2 -2
- arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py +23 -20
- arelle/plugin/validate/ESEF/ESEF_Current/DTS.py +47 -14
- arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py +100 -25
- arelle/plugin/validate/ESEF/__init__.py +20 -6
- arelle/plugin/validate/ESEF/resources/authority-validations.json +76 -9
- arelle/plugin/validate/ESEF/resources/config.xml +20 -0
- arelle/plugin/validate/NL/DisclosureSystems.py +22 -0
- arelle/plugin/validate/NL/PluginValidationDataExtension.py +27 -9
- arelle/plugin/validate/NL/ValidationPluginExtension.py +51 -7
- arelle/plugin/validate/NL/resources/config.xml +18 -0
- arelle/plugin/validate/NL/rules/br_kvk.py +17 -61
- arelle/plugin/validate/NL/rules/fg_nl.py +7 -38
- arelle/plugin/validate/NL/rules/fr_kvk.py +7 -42
- arelle/plugin/validate/NL/rules/fr_nl.py +31 -147
- arelle/plugin/validate/NL/rules/nl_kvk.py +142 -28
- arelle/plugin/validate/ROS/PluginValidationDataExtension.py +2 -0
- arelle/plugin/validate/ROS/ValidationPluginExtension.py +4 -1
- arelle/plugin/validate/ROS/rules/ros.py +41 -9
- arelle/plugin/validate/UK/ValidateUK.py +130 -66
- arelle/plugin/validate/UK/__init__.py +89 -103
- arelle/utils/EntryPointDetection.py +79 -13
- arelle/utils/PluginHooks.py +125 -0
- arelle/utils/validate/ESEFImage.py +6 -6
- arelle/utils/validate/Validation.py +18 -0
- arelle/utils/validate/ValidationPlugin.py +76 -11
- arelle/utils/validate/ValidationUtil.py +35 -3
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/METADATA +30 -20
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/RECORD +115 -191
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/licenses/LICENSE.md +0 -3
- arelle/archive/CustomLogger.py +0 -43
- arelle/archive/LoadEFMvalidate.py +0 -32
- arelle/archive/LoadSavePreLbCsv.py +0 -26
- arelle/archive/LoadValidate.cs +0 -31
- arelle/archive/LoadValidate.py +0 -36
- arelle/archive/LoadValidateCmdLine.java +0 -69
- arelle/archive/LoadValidatePostedZip.java +0 -57
- arelle/archive/LoadValidateWebService.java +0 -34
- arelle/archive/SaveTableToExelle.py +0 -140
- arelle/archive/TR3toTR4.py +0 -88
- arelle/archive/plugin/ESEF_2022/__init__.py +0 -47
- arelle/archive/plugin/bigInstance.py +0 -394
- arelle/archive/plugin/cmdWebServerExtension.py +0 -43
- arelle/archive/plugin/crashTest.py +0 -38
- arelle/archive/plugin/functionsXmlCreation.py +0 -106
- arelle/archive/plugin/hello_i18n.pot +0 -26
- arelle/archive/plugin/hello_i18n.py +0 -32
- arelle/archive/plugin/importTestChild1.py +0 -21
- arelle/archive/plugin/importTestChild2.py +0 -22
- arelle/archive/plugin/importTestGrandchild1.py +0 -21
- arelle/archive/plugin/importTestGrandchild2.py +0 -21
- arelle/archive/plugin/importTestImported1.py +0 -23
- arelle/archive/plugin/importTestImported11.py +0 -22
- arelle/archive/plugin/importTestParent.py +0 -48
- arelle/archive/plugin/instanceInfo.py +0 -306
- arelle/archive/plugin/loadFromOIM-2018.py +0 -1282
- arelle/archive/plugin/locale/fr/LC_MESSAGES/hello_i18n.po +0 -25
- arelle/archive/plugin/objectmaker.py +0 -285
- arelle/archive/plugin/packagedImportTest/__init__.py +0 -47
- arelle/archive/plugin/packagedImportTest/importTestChild1.py +0 -21
- arelle/archive/plugin/packagedImportTest/importTestChild2.py +0 -22
- arelle/archive/plugin/packagedImportTest/importTestGrandchild1.py +0 -21
- arelle/archive/plugin/packagedImportTest/importTestGrandchild2.py +0 -21
- arelle/archive/plugin/packagedImportTest/importTestImported1.py +0 -24
- arelle/archive/plugin/packagedImportTest/importTestImported11.py +0 -21
- arelle/archive/plugin/packagedImportTest/subdir/importTestImported111.py +0 -21
- arelle/archive/plugin/packagedImportTest/subdir/subsubdir/importTestImported1111.py +0 -21
- arelle/archive/plugin/sakaCalendar.py +0 -215
- arelle/archive/plugin/saveInstanceInfoset.py +0 -121
- arelle/archive/plugin/sphinx/FormulaGenerator.py +0 -823
- arelle/archive/plugin/sphinx/SphinxContext.py +0 -404
- arelle/archive/plugin/sphinx/SphinxEvaluator.py +0 -783
- arelle/archive/plugin/sphinx/SphinxMethods.py +0 -1287
- arelle/archive/plugin/sphinx/SphinxParser.py +0 -1093
- arelle/archive/plugin/sphinx/SphinxValidator.py +0 -163
- arelle/archive/plugin/sphinx/US-GAAP Ratios Example.xsr +0 -52
- arelle/archive/plugin/sphinx/__init__.py +0 -285
- arelle/archive/plugin/streamingExtensions.py +0 -335
- arelle/archive/plugin/updateTableLB.py +0 -242
- arelle/archive/plugin/validate/SBRnl/CustomLoader.py +0 -19
- arelle/archive/plugin/validate/SBRnl/DTS.py +0 -305
- arelle/archive/plugin/validate/SBRnl/Dimensions.py +0 -357
- arelle/archive/plugin/validate/SBRnl/Document.py +0 -799
- arelle/archive/plugin/validate/SBRnl/Filing.py +0 -467
- arelle/archive/plugin/validate/SBRnl/__init__.py +0 -75
- arelle/archive/plugin/validate/SBRnl/config.xml +0 -26
- arelle/archive/plugin/validate/SBRnl/sbr-nl-taxonomies.xml +0 -754
- arelle/archive/plugin/validate/USBestPractices.py +0 -570
- arelle/archive/plugin/validate/USCorpAction.py +0 -557
- arelle/archive/plugin/validate/USSecTagging.py +0 -337
- arelle/archive/plugin/validate/XDC/__init__.py +0 -77
- arelle/archive/plugin/validate/XDC/config.xml +0 -20
- arelle/archive/plugin/validate/XFsyntax/__init__.py +0 -64
- arelle/archive/plugin/validate/XFsyntax/xf.py +0 -2227
- arelle/archive/plugin/validate/calc2.py +0 -536
- arelle/archive/plugin/validateSchemaLxml.py +0 -156
- arelle/archive/plugin/validateTableInfoset.py +0 -52
- arelle/archive/us-gaap-dei-docType-extraction-frm.xml +0 -90
- arelle/archive/us-gaap-dei-ratio-cash-frm.xml +0 -150
- arelle/examples/plugin/formulaSuiteConverter.py +0 -212
- arelle/examples/plugin/functionsCustom.py +0 -59
- arelle/examples/plugin/hello_dolly.py +0 -64
- arelle/examples/plugin/multi.py +0 -58
- arelle/examples/plugin/rssSaveOim.py +0 -96
- arelle/examples/plugin/validate/XYZ/DisclosureSystems.py +0 -2
- arelle/examples/plugin/validate/XYZ/PluginValidationDataExtension.py +0 -10
- arelle/examples/plugin/validate/XYZ/ValidationPluginExtension.py +0 -49
- arelle/examples/plugin/validate/XYZ/__init__.py +0 -75
- arelle/examples/plugin/validate/XYZ/resources/config.xml +0 -16
- arelle/examples/plugin/validate/XYZ/rules/__init__.py +0 -0
- arelle/examples/plugin/validate/XYZ/rules/rules01.py +0 -110
- arelle/examples/plugin/validate/XYZ/rules/rules02.py +0 -59
- arelle/model/CommentBase.py +0 -9
- arelle/model/ElementBase.py +0 -11
- arelle/model/PIBase.py +0 -10
- arelle/model/__init__.py +0 -15
- arelle/scripts-macOS/startWebServer.command +0 -3
- arelle/scripts-unix/startWebServer.sh +0 -1
- arelle/scripts-windows/startWebServer.bat +0 -5
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/WHEEL +0 -0
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/top_level.txt +0 -0
arelle/WebCache.py
CHANGED
|
@@ -6,20 +6,29 @@ e.g., User-Agent: Sample Company Name AdminContact@<sample company domain>.com
|
|
|
6
6
|
|
|
7
7
|
'''
|
|
8
8
|
from __future__ import annotations
|
|
9
|
-
import contextlib
|
|
10
|
-
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
import calendar
|
|
11
|
+
import contextlib
|
|
12
|
+
import io
|
|
13
|
+
import json
|
|
14
|
+
import logging
|
|
15
|
+
import os
|
|
16
|
+
import posixpath
|
|
17
|
+
import shutil
|
|
18
|
+
import sys
|
|
19
|
+
import time
|
|
20
|
+
import zlib
|
|
21
|
+
from http.client import IncompleteRead
|
|
13
22
|
from pathlib import Path
|
|
14
23
|
from typing import TYPE_CHECKING, Any
|
|
15
|
-
import os, posixpath, sys, time, calendar, io, json, logging, shutil, zlib
|
|
16
|
-
import regex as re
|
|
17
|
-
from urllib.parse import quote, unquote
|
|
18
|
-
from urllib.error import URLError, HTTPError, ContentTooShortError
|
|
19
|
-
from http.client import IncompleteRead
|
|
20
24
|
from urllib import request as proxyhandlers
|
|
25
|
+
from urllib.error import ContentTooShortError, HTTPError, URLError
|
|
26
|
+
from urllib.parse import quote, unquote, urlsplit, urlunsplit
|
|
21
27
|
|
|
22
28
|
import certifi
|
|
29
|
+
import regex as re
|
|
30
|
+
import truststore
|
|
31
|
+
from filelock import FileLock, Timeout
|
|
23
32
|
|
|
24
33
|
from arelle.PythonUtil import isLegacyAbs
|
|
25
34
|
|
|
@@ -28,12 +37,6 @@ try:
|
|
|
28
37
|
except ImportError:
|
|
29
38
|
ssl = None
|
|
30
39
|
|
|
31
|
-
try:
|
|
32
|
-
import truststore
|
|
33
|
-
except ImportError:
|
|
34
|
-
# truststore requires Python > 3.9
|
|
35
|
-
truststore = None
|
|
36
|
-
|
|
37
40
|
from arelle.FileSource import SERVER_WEB_CACHE, archiveFilenameParts
|
|
38
41
|
from arelle.PluginManager import pluginClassMethods
|
|
39
42
|
from arelle.UrlUtil import isHttpUrl
|
|
@@ -274,8 +277,7 @@ class WebCache:
|
|
|
274
277
|
self.http_auth_handler = proxyhandlers.HTTPBasicAuthHandler()
|
|
275
278
|
proxyHandlers = [self.proxy_handler, self.proxy_auth_handler, self.http_auth_handler]
|
|
276
279
|
if ssl:
|
|
277
|
-
|
|
278
|
-
context = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT) if truststore else ssl.create_default_context()
|
|
280
|
+
context = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
279
281
|
# Include certifi certificates (Mozilla’s carefully curated
|
|
280
282
|
# collection) for systems with outdated certs.
|
|
281
283
|
context.load_verify_locations(cafile=certifi.where())
|
|
@@ -567,14 +569,16 @@ class WebCache:
|
|
|
567
569
|
:param url:
|
|
568
570
|
:return: `url` with scheme-specific-part quoted except for parameter separators
|
|
569
571
|
"""
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
# RFC 3986: https://www.ietf.org/rfc/rfc3986.txt
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
572
|
+
parts = urlsplit(url)
|
|
573
|
+
|
|
574
|
+
# RFC 3986 safe characters: https://www.ietf.org/rfc/rfc3986.txt
|
|
575
|
+
pathSafe = "/:@!$&'()*+,;=" # path allows sub-delims, ":" and "@"
|
|
576
|
+
querySafe = "&=:/?@!$'()*+,;[]" # query allows pchar + "/" + "?"
|
|
577
|
+
|
|
578
|
+
quotedPath = quote(parts.path, safe=pathSafe)
|
|
579
|
+
quotedQuery = quote(parts.query, safe=querySafe)
|
|
580
|
+
|
|
581
|
+
return urlunsplit((parts.scheme, parts.netloc, quotedPath, quotedQuery, parts.fragment))
|
|
578
582
|
|
|
579
583
|
@staticmethod
|
|
580
584
|
def _getFileTimestamp(path: str) -> float:
|
arelle/XbrlConst.py
CHANGED
|
@@ -22,10 +22,13 @@ _tuple = tuple # type: ignore[type-arg]
|
|
|
22
22
|
xsd = "http://www.w3.org/2001/XMLSchema"
|
|
23
23
|
qnXsdComplexType = qname("{http://www.w3.org/2001/XMLSchema}xsd:complexType")
|
|
24
24
|
qnXsdDocumentation = qname("{http://www.w3.org/2001/XMLSchema}xsd:documentation")
|
|
25
|
+
qnXsdInclude = qname("{http://www.w3.org/2001/XMLSchema}xsd:include")
|
|
25
26
|
qnXsdImport = qname("{http://www.w3.org/2001/XMLSchema}xsd:import")
|
|
26
27
|
qnXsdSchema = qname("{http://www.w3.org/2001/XMLSchema}xsd:schema")
|
|
27
28
|
qnXsdAppinfo = qname("{http://www.w3.org/2001/XMLSchema}xsd:appinfo")
|
|
28
29
|
qnXsdDefaultType = qname("{http://www.w3.org/2001/XMLSchema}xsd:anyType")
|
|
30
|
+
qnXsdElement = qname("{http://www.w3.org/2001/XMLSchema}xsd:element")
|
|
31
|
+
qnXsdAttribute = qname("{http://www.w3.org/2001/XMLSchema}xsd:attribute")
|
|
29
32
|
xsi = "http://www.w3.org/2001/XMLSchema-instance"
|
|
30
33
|
qnXsiNil = qname(xsi, "xsi:nil") # need default prefix in qname
|
|
31
34
|
qnXsiType = qname(xsi, "xsi:type")
|
|
@@ -127,6 +130,7 @@ qnXlinkArcRole = qname("{http://www.w3.org/1999/xlink}xlink:arcrole")
|
|
|
127
130
|
qnXlinkFrom = qname("{http://www.w3.org/1999/xlink}xlink:from")
|
|
128
131
|
qnXlinkHref = qname("{http://www.w3.org/1999/xlink}xlink:href")
|
|
129
132
|
qnXlinkLabel = qname("{http://www.w3.org/1999/xlink}xlink:label")
|
|
133
|
+
qnXlinkRole = qname("{http://www.w3.org/1999/xlink}xlink:role")
|
|
130
134
|
qnXlinkTo = qname("{http://www.w3.org/1999/xlink}xlink:to")
|
|
131
135
|
qnXlinkType = qname("{http://www.w3.org/1999/xlink}xlink:type")
|
|
132
136
|
xl = "http://www.xbrl.org/2003/XLink"
|
|
@@ -138,6 +142,9 @@ qnXlLocatorType = qname("{http://www.xbrl.org/2003/XLink}xl:locatorType")
|
|
|
138
142
|
qnXlResourceType = qname("{http://www.xbrl.org/2003/XLink}xl:resourceType")
|
|
139
143
|
qnXlArcType = qname("{http://www.xbrl.org/2003/XLink}xl:arcType")
|
|
140
144
|
xhtml = "http://www.w3.org/1999/xhtml"
|
|
145
|
+
qnXhtmlMeta = qname("{http://www.w3.org/1999/xhtml}meta")
|
|
146
|
+
qnXhtmlImg = qname("{http://www.w3.org/1999/xhtml}img")
|
|
147
|
+
qnXhtmlDel = qname("{http://www.w3.org/1999/xhtml}del")
|
|
141
148
|
ixbrl = "http://www.xbrl.org/2008/inlineXBRL"
|
|
142
149
|
ixbrl11 = "http://www.xbrl.org/2013/inlineXBRL"
|
|
143
150
|
ixbrlAll = {ixbrl, ixbrl11}
|
|
@@ -178,6 +185,21 @@ ixAttributes = set(
|
|
|
178
185
|
"tupleID",
|
|
179
186
|
)
|
|
180
187
|
)
|
|
188
|
+
ixbrlTargetElements = frozenset({
|
|
189
|
+
qnIXbrlFraction,
|
|
190
|
+
qnIXbrlNonFraction,
|
|
191
|
+
qnIXbrlNonNumeric,
|
|
192
|
+
qnIXbrlResources,
|
|
193
|
+
qnIXbrlTuple,
|
|
194
|
+
})
|
|
195
|
+
ixbrl11TargetElements = frozenset({
|
|
196
|
+
qnIXbrl11Fraction,
|
|
197
|
+
qnIXbrl11NonFraction,
|
|
198
|
+
qnIXbrl11NonNumeric,
|
|
199
|
+
qnIXbrl11Resources,
|
|
200
|
+
qnIXbrl11Tuple,
|
|
201
|
+
})
|
|
202
|
+
ixbrlAllTargetElements = ixbrlTargetElements | ixbrl11TargetElements
|
|
181
203
|
conceptLabel = "http://www.xbrl.org/2003/arcrole/concept-label"
|
|
182
204
|
conceptReference = "http://www.xbrl.org/2003/arcrole/concept-reference"
|
|
183
205
|
footnote = "http://www.xbrl.org/2003/role/footnote"
|
arelle/XmlUtil.py
CHANGED
|
@@ -285,9 +285,8 @@ def escapedNode(
|
|
|
285
285
|
for n,v in sorted(elt.items(), key=lambda item: item[0]):
|
|
286
286
|
if n in uriAttrs:
|
|
287
287
|
v = resolveHtmlUri(elt, n, v).replace(" ", "%20") # %20 replacement needed for conformance test passing
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
cast(str, v).replace("&","&").replace('"', '"')))
|
|
288
|
+
s.append(' {0}="{1}"'.format(qname(elt, n),
|
|
289
|
+
v.replace("&","&").replace('"', '"')))
|
|
291
290
|
if not start and empty:
|
|
292
291
|
if selfClosable(elt):
|
|
293
292
|
s.append('/')
|
|
@@ -401,9 +400,7 @@ def ancestors(
|
|
|
401
400
|
ancestorLocalNames: str | tuple[str, ...] | None = None
|
|
402
401
|
) -> list[ModelObject]:
|
|
403
402
|
if ancestorNamespaceURI is None and ancestorLocalNames is None:
|
|
404
|
-
return
|
|
405
|
-
cast(ModelObject, ancestor) for ancestor in element.iterancestors()
|
|
406
|
-
]
|
|
403
|
+
return list(element.iterancestors())
|
|
407
404
|
ancestors = []
|
|
408
405
|
wildNamespaceURI = not ancestorNamespaceURI or ancestorNamespaceURI == '*'
|
|
409
406
|
treeElt = element.getparent()
|
|
@@ -635,13 +632,13 @@ def schemaBaseTypeDerivedFrom(
|
|
|
635
632
|
return child.get("base") # str | None
|
|
636
633
|
elif child.tag == "{http://www.w3.org/2001/XMLSchema}union":
|
|
637
634
|
return (child.get("memberTypes") or "").split() + [
|
|
638
|
-
schemaBaseTypeDerivedFrom(
|
|
635
|
+
schemaBaseTypeDerivedFrom(_child)
|
|
639
636
|
for _child in child.iterchildren(tag="{http://www.w3.org/2001/XMLSchema}simpleType")] # list[str | QName | list[This func return] | None]
|
|
640
637
|
elif child.tag in ("{http://www.w3.org/2001/XMLSchema}complexType",
|
|
641
638
|
"{http://www.w3.org/2001/XMLSchema}simpleType",
|
|
642
639
|
"{http://www.w3.org/2001/XMLSchema}complexContent",
|
|
643
640
|
"{http://www.w3.org/2001/XMLSchema}simpleContent"):
|
|
644
|
-
return schemaBaseTypeDerivedFrom(
|
|
641
|
+
return schemaBaseTypeDerivedFrom(child)
|
|
645
642
|
return None
|
|
646
643
|
|
|
647
644
|
def schemaFacets(
|
|
@@ -846,7 +843,7 @@ def copyIxFootnoteHtml(
|
|
|
846
843
|
if contAt is not None:
|
|
847
844
|
copyIxFootnoteHtml(contAt, tgtHtml, targetModelDocument, withText=withText, isContinChainElt=True, tgtStack=tgtStack, srcLevel=0)
|
|
848
845
|
|
|
849
|
-
def addComment(parent:
|
|
846
|
+
def addComment(parent: etree._Element, commentText: str) -> None:
|
|
850
847
|
comment = str(commentText)
|
|
851
848
|
if '--' in comment: # replace -- with - - (twice, in case more than 3 '-' together)
|
|
852
849
|
comment = comment.replace('--', '- -').replace('--', '- -')
|
|
@@ -854,7 +851,7 @@ def addComment(parent: ModelObject, commentText: str) -> None:
|
|
|
854
851
|
parent.append(child)
|
|
855
852
|
|
|
856
853
|
def addProcessingInstruction(
|
|
857
|
-
parent:
|
|
854
|
+
parent: etree._Element,
|
|
858
855
|
piTarget: str | bytes,
|
|
859
856
|
piText: str,
|
|
860
857
|
insertBeforeChildElements: bool = True,
|
|
@@ -909,13 +906,10 @@ def setXmlns(modelDocument: etree._ElementTree | ModelDocument, prefix: str | No
|
|
|
909
906
|
if root.tag == 'nsmap': # already have an xmlns-extension root element
|
|
910
907
|
newmap = root.nsmap
|
|
911
908
|
newmap[prefix] = namespaceURI
|
|
912
|
-
|
|
913
|
-
# but '' for default ns is not accepted by lxml nsmap arg and lxml produces and error
|
|
914
|
-
# see https://github.com/lxml/lxml-stubs/blob/0a9b6099dd39b298fd0ff897dbcd4fed632d8776/lxml-stubs/etree.pyi#L69
|
|
915
|
-
newroot = etree.Element('nsmap', nsmap=newmap) # type: ignore[arg-type] # above note
|
|
909
|
+
newroot = etree.Element('nsmap', nsmap=newmap)
|
|
916
910
|
newroot.extend(root)
|
|
917
911
|
else: # new xmlns-extension root
|
|
918
|
-
newroot = etree.Element('nsmap', nsmap={prefix: namespaceURI})
|
|
912
|
+
newroot = etree.Element('nsmap', nsmap={prefix: namespaceURI})
|
|
919
913
|
comments = []
|
|
920
914
|
comment = root.getprevious()
|
|
921
915
|
while isinstance(comment, etree._Comment):
|
|
@@ -939,9 +933,9 @@ def sortKey(
|
|
|
939
933
|
if parentElement is not None:
|
|
940
934
|
for childLocalName in childLocalNames if isinstance(childLocalNames,tuple) else (childLocalNames,):
|
|
941
935
|
for child in parentElement.iterdescendants(tag="{{{0}}}{1}".format(childNamespaceUri,childLocalName)):
|
|
942
|
-
value = text(
|
|
936
|
+
value = text(child)
|
|
943
937
|
if qnames:
|
|
944
|
-
_value = prefixedNameToClarkNotation(
|
|
938
|
+
_value = prefixedNameToClarkNotation(child, value)
|
|
945
939
|
assert isinstance(_value, str)
|
|
946
940
|
value = _value
|
|
947
941
|
if childAttributeName is not None:
|
|
@@ -1156,7 +1150,7 @@ def elementTagnamesPath(element: etree._Element | ModelObject | None) -> str:
|
|
|
1156
1150
|
# returns clark notation absolute path without element sequences
|
|
1157
1151
|
tagnamesPath: list[str] = []
|
|
1158
1152
|
while (element is not None):
|
|
1159
|
-
tagnamesPath.insert(0, element.tag)
|
|
1153
|
+
tagnamesPath.insert(0, cast(str, element.tag))
|
|
1160
1154
|
element = element.getparent()
|
|
1161
1155
|
return "/".join(tagnamesPath)
|
|
1162
1156
|
|
|
@@ -1235,7 +1229,8 @@ def writexml(
|
|
|
1235
1229
|
if skipInvalid and getattr(node, "xValid", VALID) == INVALID:
|
|
1236
1230
|
return
|
|
1237
1231
|
else:
|
|
1238
|
-
|
|
1232
|
+
nodeTag = cast(str, node.tag)
|
|
1233
|
+
ns, sep, localName = nodeTag.partition('}')
|
|
1239
1234
|
if sep:
|
|
1240
1235
|
ns = ns[1:]
|
|
1241
1236
|
prefix = xmlnsprefix(node,ns)
|
|
@@ -1258,7 +1253,7 @@ def writexml(
|
|
|
1258
1253
|
else:
|
|
1259
1254
|
attrs["xmlns"] = ns
|
|
1260
1255
|
for aTag,aValue in node.items():
|
|
1261
|
-
ns, sep, localName =
|
|
1256
|
+
ns, sep, localName = aTag.partition('}')
|
|
1262
1257
|
if sep:
|
|
1263
1258
|
prefix = xmlnsprefix(node,ns[1:])
|
|
1264
1259
|
if prefix:
|
|
@@ -1267,7 +1262,7 @@ def writexml(
|
|
|
1267
1262
|
prefixedName = localName
|
|
1268
1263
|
else:
|
|
1269
1264
|
prefixedName = ns
|
|
1270
|
-
attrs[prefixedName] =
|
|
1265
|
+
attrs[prefixedName] = aValue
|
|
1271
1266
|
aSortedNames = sorted(attrs.keys())
|
|
1272
1267
|
|
|
1273
1268
|
# should attribute names be indented on separate lines?
|
arelle/XmlValidate.py
CHANGED
|
@@ -268,9 +268,7 @@ def validate(
|
|
|
268
268
|
presentAttributes = set()
|
|
269
269
|
# validate attributes
|
|
270
270
|
# find missing attributes for default values
|
|
271
|
-
for
|
|
272
|
-
attrTag: str = cast(str, attrTag_)
|
|
273
|
-
attrValue: str = cast(str, attrValue_)
|
|
271
|
+
for attrTag, attrValue in elt.items():
|
|
274
272
|
qn = qnameClarkName(attrTag)
|
|
275
273
|
#qn = qname(attrTag, noPrefixIsNoNamespace=True)
|
|
276
274
|
baseXsdAttrType = None
|
|
@@ -458,9 +456,8 @@ def validateValue(
|
|
|
458
456
|
xValue = sValue = value
|
|
459
457
|
xValid = VALID_ID
|
|
460
458
|
elif baseXsdType == "anyURI":
|
|
461
|
-
if value:
|
|
462
|
-
|
|
463
|
-
raise ValueError("IETF RFC 2396 4.3 syntax")
|
|
459
|
+
if not UrlUtil.isValidUriReference(value):
|
|
460
|
+
raise ValueError("IETF RFC 2396 4.3 syntax")
|
|
464
461
|
# encode PSVI xValue similarly to Xerces and other implementations
|
|
465
462
|
xValue = anyURI(UrlUtil.anyUriQuoteForPSVI(value))
|
|
466
463
|
sValue = value
|
|
@@ -703,8 +700,8 @@ class lxmlSchemaResolver(etree.Resolver):
|
|
|
703
700
|
if xml:
|
|
704
701
|
return self.resolve_string(xml, context, base_url=_url)
|
|
705
702
|
else: # probably no active modelXbrl yet, such as when loading packages, use url
|
|
706
|
-
return self.resolve_filename(url, context)
|
|
707
|
-
return self.resolve_empty(context)
|
|
703
|
+
return self.resolve_filename(url, context)
|
|
704
|
+
return self.resolve_empty(context)
|
|
708
705
|
|
|
709
706
|
def lxmlResolvingParser(cntlr: Cntlr, modelXbrl: ModelXbrl | None = None) -> etree.XMLParser:
|
|
710
707
|
parser = etree.XMLParser(resolve_entities=False)
|
|
@@ -757,7 +754,7 @@ def lxmlSchemaValidate(modelDocument: ModelDocument, extraSchema : str | None =
|
|
|
757
754
|
for key, val in docTree.getroot().nsmap.items()
|
|
758
755
|
if key
|
|
759
756
|
}
|
|
760
|
-
for e in err.error_log:
|
|
757
|
+
for e in err.error_log:
|
|
761
758
|
if not any(s in e.message for s in (": The QName value", "is not a valid value of the atomic type 'xs:QName'")):
|
|
762
759
|
# do newer lxml validations have QName whitespace collapsing issue?
|
|
763
760
|
userFriendlyElementPath = ''
|
arelle/_version.py
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
3
|
|
|
4
|
-
__all__ = [
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
5
12
|
|
|
6
13
|
TYPE_CHECKING = False
|
|
7
14
|
if TYPE_CHECKING:
|
|
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
|
|
|
9
16
|
from typing import Union
|
|
10
17
|
|
|
11
18
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
12
20
|
else:
|
|
13
21
|
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
14
23
|
|
|
15
24
|
version: str
|
|
16
25
|
__version__: str
|
|
17
26
|
__version_tuple__: VERSION_TUPLE
|
|
18
27
|
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
19
30
|
|
|
20
|
-
__version__ = version = '2.
|
|
21
|
-
__version_tuple__ = version_tuple = (2,
|
|
31
|
+
__version__ = version = '2.38.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 38, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
arelle/api/Session.py
CHANGED
|
@@ -8,7 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
import logging
|
|
9
9
|
import threading
|
|
10
10
|
from types import TracebackType
|
|
11
|
-
from typing import Any, BinaryIO
|
|
11
|
+
from typing import Any, BinaryIO, TypeVar
|
|
12
12
|
|
|
13
13
|
from arelle import PackageManager, PluginManager
|
|
14
14
|
from arelle.CntlrCmdLine import CntlrCmdLine, createCntlrAndPreloadPlugins
|
|
@@ -18,6 +18,9 @@ from arelle.RuntimeOptions import RuntimeOptions
|
|
|
18
18
|
|
|
19
19
|
_session_lock = threading.Lock()
|
|
20
20
|
|
|
21
|
+
# typing.Self can be used once Python 3.10 support is dropped.
|
|
22
|
+
Self = TypeVar("Self", bound="Session")
|
|
23
|
+
|
|
21
24
|
|
|
22
25
|
class Session:
|
|
23
26
|
"""
|
|
@@ -46,7 +49,7 @@ class Session:
|
|
|
46
49
|
"Session objects cannot be shared between threads. Create a new Session instance in each thread."
|
|
47
50
|
)
|
|
48
51
|
|
|
49
|
-
def __enter__(self) ->
|
|
52
|
+
def __enter__(self: Self) -> Self:
|
|
50
53
|
return self
|
|
51
54
|
|
|
52
55
|
def __exit__(
|
|
@@ -110,6 +113,12 @@ class Session:
|
|
|
110
113
|
) -> bool:
|
|
111
114
|
"""
|
|
112
115
|
Perform a run using the given options.
|
|
116
|
+
When using a sourceZipStream, the name attribute on it will be checked
|
|
117
|
+
and, if present, assumed to be the effective name of the zip file the
|
|
118
|
+
stream represents. When validating '.xbri' files, via a sourceZipStream,
|
|
119
|
+
it is important to set this name attribute to avoid
|
|
120
|
+
rpe:documentTypeFileExtensionMismatch errors.
|
|
121
|
+
|
|
113
122
|
:param options: Options to use for the run.
|
|
114
123
|
:param sourceZipStream: Optional stream to read source data from.
|
|
115
124
|
:param responseZipStream: Options stream to write response data to.
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
<xs:attribute name="deiFilerNameElement" use="optional" type="xs:NCName"/>
|
|
52
52
|
<xs:attribute name="deiNamespacePattern" use="optional"/>
|
|
53
53
|
<xs:attribute name="description" />
|
|
54
|
+
<xs:attribute name="keepOpen" type="xs:boolean"/>
|
|
54
55
|
<xs:attribute name="identifierSchemePattern" use="optional"/>
|
|
55
56
|
<xs:attribute name="identifierValueName" use="optional"/>
|
|
56
57
|
<xs:attribute name="identifierValuePattern" use="optional"/>
|
|
@@ -74,6 +75,7 @@
|
|
|
74
75
|
<xs:attribute name="standardTaxonomyDatabase" />
|
|
75
76
|
<xs:attribute name="standardTaxonomyUrlPattern" />
|
|
76
77
|
<xs:attribute name="options" />
|
|
78
|
+
<xs:attribute name="arcroleCyclesAllowed" type="xs:string"/>
|
|
77
79
|
</xs:complexType>
|
|
78
80
|
</xs:element>
|
|
79
81
|
</xs:schema>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
|
6
|
+
<true/>
|
|
7
|
+
</dict>
|
|
8
|
+
</plist>
|
|
@@ -54,7 +54,7 @@ def loadCsvTestcase(
|
|
|
54
54
|
if tuple(header) != CSV_TESTCASE_HEADER:
|
|
55
55
|
# CSV doesn't have a recognized testcase header.
|
|
56
56
|
raise CSVTestcaseException(f"CSV file {filepath} doesn't have test case header: {CSV_TESTCASE_HEADER}, first row {header}")
|
|
57
|
-
testcaseElement = etree.Element("testcase", nsmap=TESTCASE_NAMESPACES_BY_PREFIX)
|
|
57
|
+
testcaseElement = etree.Element("testcase", nsmap=TESTCASE_NAMESPACES_BY_PREFIX)
|
|
58
58
|
document = ModelDocument.create(
|
|
59
59
|
modelXbrl,
|
|
60
60
|
ModelDocument.Type.TESTCASE,
|
arelle/formula/XPathContext.py
CHANGED
|
@@ -781,11 +781,11 @@ class XPathContext:
|
|
|
781
781
|
elif axis.endswith("-sibling"):
|
|
782
782
|
if isinstance(node, ModelObject):
|
|
783
783
|
targetNodes = [
|
|
784
|
-
sibling
|
|
784
|
+
sibling
|
|
785
785
|
for sibling in node.itersiblings(preceding=axis.startswith("preceding"))
|
|
786
786
|
if (
|
|
787
|
-
(not ns or ns == sibling.namespaceURI or ns == "*")
|
|
788
|
-
and (localname == sibling.localName or localname == "*")
|
|
787
|
+
(not ns or ns == sibling.namespaceURI or ns == "*")
|
|
788
|
+
and (localname == sibling.localName or localname == "*")
|
|
789
789
|
)
|
|
790
790
|
]
|
|
791
791
|
elif axis == "preceding":
|
|
@@ -7,6 +7,8 @@ import logging
|
|
|
7
7
|
from collections import defaultdict
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
|
+
from arelle import UrlUtil
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
class LogFormatter(logging.Formatter):
|
|
12
14
|
def __init__(self, fmt: str | None = None, datefmt: str | None = None) -> None:
|
|
@@ -39,7 +41,7 @@ def logRefsFileLines(refs: list[dict[str, Any]]) -> str:
|
|
|
39
41
|
for ref in refs:
|
|
40
42
|
href = ref.get("href")
|
|
41
43
|
if href:
|
|
42
|
-
hrefWithoutFakeIxdsPrefix =
|
|
44
|
+
hrefWithoutFakeIxdsPrefix = UrlUtil.stripIxdsSurrogatePrefix(href)
|
|
43
45
|
fileLines[hrefWithoutFakeIxdsPrefix.partition("#")[0]].add(ref.get("sourceLine") or 0)
|
|
44
46
|
return ", ".join(file + " " + ', '.join(str(line)
|
|
45
47
|
for line in sorted(lines, key=lambda l: l)
|
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
import json
|
|
8
8
|
import os
|
|
9
9
|
import zipfile
|
|
10
|
-
from collections import
|
|
10
|
+
from collections import defaultdict
|
|
11
11
|
from dataclasses import dataclass
|
|
12
12
|
from pathlib import Path, PurePosixPath
|
|
13
13
|
from typing import TYPE_CHECKING, Any, cast
|
|
@@ -19,13 +19,22 @@ if TYPE_CHECKING:
|
|
|
19
19
|
from arelle.FileSource import FileSource
|
|
20
20
|
|
|
21
21
|
|
|
22
|
+
def pathsContainReportsDirectory(paths: set[str], topLevelDir: str) -> bool:
|
|
23
|
+
reportDirectory = f"{topLevelDir}/{Const.REPORTS_DIRECTORY}"
|
|
24
|
+
if reportDirectory in paths:
|
|
25
|
+
return True
|
|
26
|
+
reportDirectory = f"{reportDirectory}/"
|
|
27
|
+
return any(path.startswith(reportDirectory) for path in paths)
|
|
28
|
+
|
|
22
29
|
def getReportPackageTopLevelDirectory(filesource: FileSource) -> str | None:
|
|
23
30
|
packageEntries = set(filesource.dir or [])
|
|
24
|
-
potentialTopLevelReportDirs =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
potentialTopLevelReportDirs = set()
|
|
32
|
+
for topLevelDir in PackageUtils.getPackageTopLevelDirectories(filesource):
|
|
33
|
+
if (
|
|
34
|
+
f"{topLevelDir}/{Const.REPORT_PACKAGE_FILE}" in packageEntries or
|
|
35
|
+
pathsContainReportsDirectory(packageEntries, topLevelDir)
|
|
36
|
+
):
|
|
37
|
+
potentialTopLevelReportDirs.add(topLevelDir)
|
|
29
38
|
if len(potentialTopLevelReportDirs) == 1:
|
|
30
39
|
return next(iter(potentialTopLevelReportDirs))
|
|
31
40
|
return None
|
|
@@ -98,7 +107,7 @@ def getAllReportEntries(filesource: FileSource, stld: str | None) -> list[Report
|
|
|
98
107
|
if not isinstance(filesource.fs, zipfile.ZipFile):
|
|
99
108
|
return None
|
|
100
109
|
entries = [f.orig_filename for f in filesource.fs.infolist()]
|
|
101
|
-
if not
|
|
110
|
+
if not pathsContainReportsDirectory(set(entries), stld):
|
|
102
111
|
return None
|
|
103
112
|
topReportEntries = []
|
|
104
113
|
entriesBySubDir = defaultdict(list)
|
|
@@ -206,15 +215,19 @@ class ReportPackage:
|
|
|
206
215
|
if reportPackageJsonFile:
|
|
207
216
|
reportPackageJson = getPackageJson(filesource, reportPackageJsonFile)
|
|
208
217
|
reports = getAllReportEntries(filesource, stld)
|
|
209
|
-
|
|
218
|
+
identifedByInspection = reportPackageJsonFile is not None or reports is not None
|
|
219
|
+
if reportType == Const.ReportType.UNCONSTRAINED_REPORT_PACKAGE and not identifedByInspection:
|
|
220
|
+
# A zip file, but not a report package.
|
|
210
221
|
return None
|
|
211
|
-
|
|
222
|
+
if reportType is None:
|
|
223
|
+
# Archive with unrecognized file extension.
|
|
224
|
+
if not identifedByInspection:
|
|
225
|
+
# Not a report package
|
|
226
|
+
return None
|
|
227
|
+
# Invalid file extension. Validate as report package and block loading reports.
|
|
228
|
+
reports = None
|
|
212
229
|
if reports is not None and any(report.isTopLevel for report in reports):
|
|
213
230
|
reports = [report for report in reports if report.isTopLevel]
|
|
214
|
-
if any(subdirCount > 1 for subdirCount in reportEntriesBySubDir.values()):
|
|
215
|
-
return None
|
|
216
|
-
if reportType and reportType.isConstrained and len(reports or []) > 1:
|
|
217
|
-
return None
|
|
218
231
|
return ReportPackage(
|
|
219
232
|
reportPackageZip=filesource.fs,
|
|
220
233
|
stld=stld,
|
|
@@ -36,7 +36,6 @@ REPORT_PACKAGE_EXTENSIONS = frozenset(
|
|
|
36
36
|
|
|
37
37
|
REPORT_PACKAGE_FILE = f"{META_INF_DIRECTORY}/reportPackage.json"
|
|
38
38
|
REPORTS_DIRECTORY = "reports"
|
|
39
|
-
REPORT_PACKAGE_PATHS = [REPORT_PACKAGE_FILE, f"{REPORTS_DIRECTORY}/"]
|
|
40
39
|
|
|
41
40
|
XBRL_2_1_REPORT_FILE_EXTENSION = ".xbrl"
|
|
42
41
|
JSON_REPORT_FILE_EXTENSION = ".json"
|
|
@@ -140,7 +140,7 @@ from arelle.PluginManager import pluginClassMethods
|
|
|
140
140
|
from arelle.PrototypeDtsObject import ArcPrototype, LocPrototype
|
|
141
141
|
from arelle.PythonUtil import attrdict, isLegacyAbs
|
|
142
142
|
from arelle.RuntimeOptions import RuntimeOptions
|
|
143
|
-
from arelle.UrlUtil import isHttpUrl
|
|
143
|
+
from arelle.UrlUtil import IXDS_DOC_SEPARATOR, IXDS_SURROGATE, isHttpUrl
|
|
144
144
|
from arelle.utils.EntryPointDetection import filesourceEntrypointFiles
|
|
145
145
|
from arelle.ValidateDuplicateFacts import DeduplicationType
|
|
146
146
|
from arelle.ValidateFilingText import CDATApattern
|
|
@@ -156,8 +156,6 @@ from arelle.XmlValidate import NONE, VALID
|
|
|
156
156
|
from arelle.XmlValidate import validate as xmlValidate
|
|
157
157
|
|
|
158
158
|
DEFAULT_TARGET = "(default)"
|
|
159
|
-
IXDS_SURROGATE = "_IXDS#?#" # surrogate (fake) file name for inline XBRL doc set (IXDS)
|
|
160
|
-
IXDS_DOC_SEPARATOR = "#?#" # the files of the document set follow the above "surrogate" with these separators
|
|
161
159
|
|
|
162
160
|
MINIMUM_IXDS_DOC_COUNT = 2 # make this 2 to cause single-documents to be processed without a document set object
|
|
163
161
|
|
|
@@ -248,7 +246,7 @@ def inlineXbrlDocumentSetLoader(modelXbrl, normalizedUri, filepath, isEntry=Fals
|
|
|
248
246
|
for url in modelXbrl.ixdsDocUrls:
|
|
249
247
|
xml.append("<instance>{}</instance>\n".format(url))
|
|
250
248
|
xml.append("</instances>\n")
|
|
251
|
-
ixdocset = create(modelXbrl, Type.INLINEXBRLDOCUMENTSET, docsetUrl, isEntry=True, initialXml="".join(xml))
|
|
249
|
+
ixdocset = create(modelXbrl, Type.INLINEXBRLDOCUMENTSET, docsetUrl, isEntry=True, initialXml="".join(xml), entrypoint=kwargs.get('entrypoint'))
|
|
252
250
|
ixdocset.type = Type.INLINEXBRLDOCUMENTSET
|
|
253
251
|
ixdocset.targetDocumentPreferredFilename = None # possibly no inline docs in this doc set
|
|
254
252
|
for i, elt in enumerate(ixdocset.xmlRootElement.iter(tag="instance")):
|
|
@@ -739,7 +737,22 @@ def commandLineOptionExtender(parser, *args, **kwargs):
|
|
|
739
737
|
def commandLineFilingStart(cntlr, options, filesource, entrypointFiles, *args, **kwargs):
|
|
740
738
|
global skipExpectedInstanceComparison
|
|
741
739
|
skipExpectedInstanceComparison = getattr(options, "skipExpectedInstanceComparison", False)
|
|
742
|
-
|
|
740
|
+
filingStart(
|
|
741
|
+
cntlr,
|
|
742
|
+
entrypointFiles,
|
|
743
|
+
getattr(options, "inlineTarget", None),
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
def guiFilingStart(cntlr, filesource, entrypointFiles, *args, **kwargs):
|
|
747
|
+
global skipExpectedInstanceComparison
|
|
748
|
+
skipExpectedInstanceComparison = False
|
|
749
|
+
filingStart(
|
|
750
|
+
cntlr,
|
|
751
|
+
entrypointFiles,
|
|
752
|
+
inlineTarget=None
|
|
753
|
+
)
|
|
754
|
+
|
|
755
|
+
def filingStart(cntlr, entrypointFiles, inlineTarget):
|
|
743
756
|
if inlineTarget:
|
|
744
757
|
if isinstance(entrypointFiles, dict):
|
|
745
758
|
entrypointFiles = [entrypointFiles]
|
|
@@ -1018,6 +1031,7 @@ __pluginInfo__ = {
|
|
|
1018
1031
|
'InlineDocumentSet.Discovery': inlineDocsetDiscovery,
|
|
1019
1032
|
'InlineDocumentSet.Url.Separator': inlineDocsetUrlSeparator,
|
|
1020
1033
|
'InlineDocumentSet.CreateTargetInstance': createTargetInstance,
|
|
1034
|
+
'CntlrWinMain.Filing.Start': guiFilingStart,
|
|
1021
1035
|
'CntlrWinMain.Menu.File.Open': fileOpenMenuEntender,
|
|
1022
1036
|
'CntlrWinMain.Menu.Tools': saveTargetDocumentMenuEntender,
|
|
1023
1037
|
'CntlrCmdLine.Options': commandLineOptionExtender,
|
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
ARL_2022_PREVIEW = "arl-2022-preview"
|
|
2
2
|
ARL_2024_PREVIEW = "arl-2024-preview"
|
|
3
3
|
ARL_2024_MULTI_TARGET_PREVIEW = "arl-2024-multi-target-preview"
|
|
4
|
+
DKFIN_2024_MULTI_TARGET_PREVIEW = "dkfin-2024-multi-target-preview"
|
|
5
|
+
|
|
6
|
+
ALL_DISCLOSURE_SYSTEMS = [
|
|
7
|
+
ARL_2022_PREVIEW,
|
|
8
|
+
ARL_2024_PREVIEW,
|
|
9
|
+
ARL_2024_MULTI_TARGET_PREVIEW,
|
|
10
|
+
DKFIN_2024_MULTI_TARGET_PREVIEW
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
ARL_DISCLOSURE_SYSTEMS = [
|
|
14
|
+
ARL_2022_PREVIEW,
|
|
15
|
+
ARL_2024_PREVIEW,
|
|
16
|
+
ARL_2024_MULTI_TARGET_PREVIEW
|
|
17
|
+
]
|
|
4
18
|
|
|
5
19
|
STAND_ALONE_DISCLOSURE_SYSTEMS = [
|
|
6
20
|
ARL_2022_PREVIEW,
|
|
7
21
|
ARL_2024_PREVIEW
|
|
8
22
|
]
|
|
9
23
|
|
|
10
|
-
|
|
24
|
+
ARL_MULTI_TARGET_DISCLOSURE_SYSTEMS = [
|
|
11
25
|
ARL_2024_MULTI_TARGET_PREVIEW
|
|
12
26
|
]
|
|
27
|
+
|
|
28
|
+
DKFIN_MULTI_TARGET_DISCLOSURE_SYSTEMS = [
|
|
29
|
+
DKFIN_2024_MULTI_TARGET_PREVIEW
|
|
30
|
+
]
|
|
@@ -5,11 +5,10 @@ from __future__ import annotations
|
|
|
5
5
|
|
|
6
6
|
from collections import defaultdict
|
|
7
7
|
from dataclasses import dataclass
|
|
8
|
-
from typing import cast
|
|
9
8
|
|
|
10
9
|
import regex
|
|
11
10
|
|
|
12
|
-
from arelle.ModelInstanceObject import
|
|
11
|
+
from arelle.ModelInstanceObject import ModelContext, ModelFact
|
|
13
12
|
from arelle.ModelValue import QName
|
|
14
13
|
from arelle.ModelXbrl import ModelXbrl
|
|
15
14
|
from arelle.utils.PluginData import PluginData
|
|
@@ -46,7 +45,7 @@ class PluginValidationDataExtension(PluginData):
|
|
|
46
45
|
disclosureOfEquityQns: frozenset[QName]
|
|
47
46
|
consolidatedMemberQn: QName
|
|
48
47
|
consolidatedSoloDimensionQn: QName
|
|
49
|
-
cpr_regex: regex.
|
|
48
|
+
cpr_regex: regex.Pattern[str]
|
|
50
49
|
dateOfApprovalOfAnnualReportQn: QName
|
|
51
50
|
dateOfExtraordinaryDividendDistributedAfterEndOfReportingPeriod: QName
|
|
52
51
|
dateOfGeneralMeetingQn: QName
|
|
@@ -146,7 +145,6 @@ class PluginValidationDataExtension(PluginData):
|
|
|
146
145
|
return self._reportingPeriodContexts
|
|
147
146
|
contexts = []
|
|
148
147
|
for context in modelXbrl.contexts.values():
|
|
149
|
-
context = cast(ModelContext, context)
|
|
150
148
|
if context.isInstantPeriod or context.isForeverPeriod:
|
|
151
149
|
continue # Reporting period contexts can't be instant/forever contexts
|
|
152
150
|
if len(context.qnameDims) > 0:
|