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.
Files changed (204) hide show
  1. arelle/BetaFeatures.py +0 -21
  2. arelle/Cntlr.py +15 -8
  3. arelle/CntlrCmdLine.py +121 -56
  4. arelle/CntlrWinMain.py +143 -70
  5. arelle/DialogFind.py +1 -1
  6. arelle/DialogPluginManager.py +6 -4
  7. arelle/DisclosureSystem.py +7 -0
  8. arelle/ErrorManager.py +21 -6
  9. arelle/FileSource.py +11 -4
  10. arelle/FunctionIxt.py +16 -11
  11. arelle/HtmlUtil.py +5 -4
  12. arelle/LeiUtil.py +63 -43
  13. arelle/ModelDocument.py +20 -15
  14. arelle/ModelDtsObject.py +8 -0
  15. arelle/ModelInstanceObject.py +1 -1
  16. arelle/ModelObject.py +16 -18
  17. arelle/ModelObjectFactory.py +35 -17
  18. arelle/ModelXbrl.py +28 -11
  19. arelle/PluginManager.py +130 -105
  20. arelle/RuntimeOptions.py +1 -0
  21. arelle/UrlUtil.py +14 -0
  22. arelle/Validate.py +17 -12
  23. arelle/ValidateDuplicateFacts.py +3 -1
  24. arelle/ValidateFileSource.py +38 -0
  25. arelle/ValidateFilingText.py +3 -3
  26. arelle/ValidateXbrl.py +5 -2
  27. arelle/ValidateXbrlCalcs.py +210 -186
  28. arelle/ValidateXbrlDTS.py +1 -1
  29. arelle/ViewFile.py +1 -0
  30. arelle/ViewFileFactTable.py +2 -2
  31. arelle/ViewWinDTS.py +4 -1
  32. arelle/WebCache.py +28 -24
  33. arelle/XbrlConst.py +22 -0
  34. arelle/XmlUtil.py +16 -21
  35. arelle/XmlValidate.py +6 -9
  36. arelle/_version.py +16 -3
  37. arelle/api/Session.py +11 -2
  38. arelle/config/disclosuresystems.xsd +2 -0
  39. arelle/config/rosettaEntitlements.plist +8 -0
  40. arelle/conformance/CSVTestcaseLoader.py +1 -1
  41. arelle/formula/XPathContext.py +3 -3
  42. arelle/logging/formatters/LogFormatter.py +3 -1
  43. arelle/packages/report/ReportPackage.py +26 -13
  44. arelle/packages/report/ReportPackageConst.py +0 -1
  45. arelle/plugin/inlineXbrlDocumentSet.py +19 -5
  46. arelle/plugin/validate/DBA/DisclosureSystems.py +19 -1
  47. arelle/plugin/validate/DBA/PluginValidationDataExtension.py +2 -4
  48. arelle/plugin/validate/DBA/ValidationPluginExtension.py +2 -1
  49. arelle/plugin/validate/DBA/resources/config.xml +5 -0
  50. arelle/plugin/validate/DBA/rules/__init__.py +2 -2
  51. arelle/plugin/validate/DBA/rules/fr.py +19 -2
  52. arelle/plugin/validate/DBA/rules/tc.py +2 -0
  53. arelle/plugin/validate/DBA/rules/th.py +6 -0
  54. arelle/plugin/validate/DBA/rules/tm.py +18 -5
  55. arelle/plugin/validate/DBA/rules/tr.py +11 -5
  56. arelle/plugin/validate/EDINET/Constants.py +193 -9
  57. arelle/plugin/validate/EDINET/ContextRequirement.py +58 -0
  58. arelle/plugin/validate/EDINET/ControllerPluginData.py +220 -1
  59. arelle/plugin/validate/EDINET/CoverItemRequirements.py +42 -0
  60. arelle/plugin/validate/EDINET/DeiRequirements.py +118 -0
  61. arelle/plugin/validate/EDINET/FilingFormat.py +275 -0
  62. arelle/plugin/validate/EDINET/FormType.py +134 -0
  63. arelle/plugin/validate/EDINET/ManifestInstance.py +72 -5
  64. arelle/plugin/validate/EDINET/NamespaceConfig.py +50 -0
  65. arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +493 -132
  66. arelle/plugin/validate/EDINET/{InstanceType.py → ReportFolderType.py} +72 -15
  67. arelle/plugin/validate/EDINET/Statement.py +139 -0
  68. arelle/plugin/validate/EDINET/TableOfContentsBuilder.py +595 -0
  69. arelle/plugin/validate/EDINET/UploadContents.py +48 -0
  70. arelle/plugin/validate/EDINET/ValidationPluginExtension.py +20 -2
  71. arelle/plugin/validate/EDINET/__init__.py +31 -6
  72. arelle/plugin/validate/EDINET/resources/config.xml +8 -1
  73. arelle/plugin/validate/EDINET/resources/cover-item-requirements.json +793 -0
  74. arelle/plugin/validate/EDINET/resources/dei-requirements.csv +27 -0
  75. arelle/plugin/validate/EDINET/resources/edinet-taxonomies.xml +2 -0
  76. arelle/plugin/validate/EDINET/rules/contexts.py +375 -14
  77. arelle/plugin/validate/EDINET/rules/edinet.py +1934 -45
  78. arelle/plugin/validate/EDINET/rules/frta.py +122 -3
  79. arelle/plugin/validate/EDINET/rules/gfm.py +1907 -11
  80. arelle/plugin/validate/EDINET/rules/upload.py +989 -141
  81. arelle/plugin/validate/ESEF/Const.py +3 -1
  82. arelle/plugin/validate/ESEF/ESEF_2021/DTS.py +5 -0
  83. arelle/plugin/validate/ESEF/ESEF_2021/Image.py +2 -2
  84. arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py +23 -20
  85. arelle/plugin/validate/ESEF/ESEF_Current/DTS.py +47 -14
  86. arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py +100 -25
  87. arelle/plugin/validate/ESEF/__init__.py +20 -6
  88. arelle/plugin/validate/ESEF/resources/authority-validations.json +76 -9
  89. arelle/plugin/validate/ESEF/resources/config.xml +20 -0
  90. arelle/plugin/validate/NL/DisclosureSystems.py +22 -0
  91. arelle/plugin/validate/NL/PluginValidationDataExtension.py +27 -9
  92. arelle/plugin/validate/NL/ValidationPluginExtension.py +51 -7
  93. arelle/plugin/validate/NL/resources/config.xml +18 -0
  94. arelle/plugin/validate/NL/rules/br_kvk.py +17 -61
  95. arelle/plugin/validate/NL/rules/fg_nl.py +7 -38
  96. arelle/plugin/validate/NL/rules/fr_kvk.py +7 -42
  97. arelle/plugin/validate/NL/rules/fr_nl.py +31 -147
  98. arelle/plugin/validate/NL/rules/nl_kvk.py +142 -28
  99. arelle/plugin/validate/ROS/PluginValidationDataExtension.py +2 -0
  100. arelle/plugin/validate/ROS/ValidationPluginExtension.py +4 -1
  101. arelle/plugin/validate/ROS/rules/ros.py +41 -9
  102. arelle/plugin/validate/UK/ValidateUK.py +130 -66
  103. arelle/plugin/validate/UK/__init__.py +89 -103
  104. arelle/utils/EntryPointDetection.py +79 -13
  105. arelle/utils/PluginHooks.py +125 -0
  106. arelle/utils/validate/ESEFImage.py +6 -6
  107. arelle/utils/validate/Validation.py +18 -0
  108. arelle/utils/validate/ValidationPlugin.py +76 -11
  109. arelle/utils/validate/ValidationUtil.py +35 -3
  110. {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/METADATA +30 -20
  111. {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/RECORD +115 -191
  112. {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/licenses/LICENSE.md +0 -3
  113. arelle/archive/CustomLogger.py +0 -43
  114. arelle/archive/LoadEFMvalidate.py +0 -32
  115. arelle/archive/LoadSavePreLbCsv.py +0 -26
  116. arelle/archive/LoadValidate.cs +0 -31
  117. arelle/archive/LoadValidate.py +0 -36
  118. arelle/archive/LoadValidateCmdLine.java +0 -69
  119. arelle/archive/LoadValidatePostedZip.java +0 -57
  120. arelle/archive/LoadValidateWebService.java +0 -34
  121. arelle/archive/SaveTableToExelle.py +0 -140
  122. arelle/archive/TR3toTR4.py +0 -88
  123. arelle/archive/plugin/ESEF_2022/__init__.py +0 -47
  124. arelle/archive/plugin/bigInstance.py +0 -394
  125. arelle/archive/plugin/cmdWebServerExtension.py +0 -43
  126. arelle/archive/plugin/crashTest.py +0 -38
  127. arelle/archive/plugin/functionsXmlCreation.py +0 -106
  128. arelle/archive/plugin/hello_i18n.pot +0 -26
  129. arelle/archive/plugin/hello_i18n.py +0 -32
  130. arelle/archive/plugin/importTestChild1.py +0 -21
  131. arelle/archive/plugin/importTestChild2.py +0 -22
  132. arelle/archive/plugin/importTestGrandchild1.py +0 -21
  133. arelle/archive/plugin/importTestGrandchild2.py +0 -21
  134. arelle/archive/plugin/importTestImported1.py +0 -23
  135. arelle/archive/plugin/importTestImported11.py +0 -22
  136. arelle/archive/plugin/importTestParent.py +0 -48
  137. arelle/archive/plugin/instanceInfo.py +0 -306
  138. arelle/archive/plugin/loadFromOIM-2018.py +0 -1282
  139. arelle/archive/plugin/locale/fr/LC_MESSAGES/hello_i18n.po +0 -25
  140. arelle/archive/plugin/objectmaker.py +0 -285
  141. arelle/archive/plugin/packagedImportTest/__init__.py +0 -47
  142. arelle/archive/plugin/packagedImportTest/importTestChild1.py +0 -21
  143. arelle/archive/plugin/packagedImportTest/importTestChild2.py +0 -22
  144. arelle/archive/plugin/packagedImportTest/importTestGrandchild1.py +0 -21
  145. arelle/archive/plugin/packagedImportTest/importTestGrandchild2.py +0 -21
  146. arelle/archive/plugin/packagedImportTest/importTestImported1.py +0 -24
  147. arelle/archive/plugin/packagedImportTest/importTestImported11.py +0 -21
  148. arelle/archive/plugin/packagedImportTest/subdir/importTestImported111.py +0 -21
  149. arelle/archive/plugin/packagedImportTest/subdir/subsubdir/importTestImported1111.py +0 -21
  150. arelle/archive/plugin/sakaCalendar.py +0 -215
  151. arelle/archive/plugin/saveInstanceInfoset.py +0 -121
  152. arelle/archive/plugin/sphinx/FormulaGenerator.py +0 -823
  153. arelle/archive/plugin/sphinx/SphinxContext.py +0 -404
  154. arelle/archive/plugin/sphinx/SphinxEvaluator.py +0 -783
  155. arelle/archive/plugin/sphinx/SphinxMethods.py +0 -1287
  156. arelle/archive/plugin/sphinx/SphinxParser.py +0 -1093
  157. arelle/archive/plugin/sphinx/SphinxValidator.py +0 -163
  158. arelle/archive/plugin/sphinx/US-GAAP Ratios Example.xsr +0 -52
  159. arelle/archive/plugin/sphinx/__init__.py +0 -285
  160. arelle/archive/plugin/streamingExtensions.py +0 -335
  161. arelle/archive/plugin/updateTableLB.py +0 -242
  162. arelle/archive/plugin/validate/SBRnl/CustomLoader.py +0 -19
  163. arelle/archive/plugin/validate/SBRnl/DTS.py +0 -305
  164. arelle/archive/plugin/validate/SBRnl/Dimensions.py +0 -357
  165. arelle/archive/plugin/validate/SBRnl/Document.py +0 -799
  166. arelle/archive/plugin/validate/SBRnl/Filing.py +0 -467
  167. arelle/archive/plugin/validate/SBRnl/__init__.py +0 -75
  168. arelle/archive/plugin/validate/SBRnl/config.xml +0 -26
  169. arelle/archive/plugin/validate/SBRnl/sbr-nl-taxonomies.xml +0 -754
  170. arelle/archive/plugin/validate/USBestPractices.py +0 -570
  171. arelle/archive/plugin/validate/USCorpAction.py +0 -557
  172. arelle/archive/plugin/validate/USSecTagging.py +0 -337
  173. arelle/archive/plugin/validate/XDC/__init__.py +0 -77
  174. arelle/archive/plugin/validate/XDC/config.xml +0 -20
  175. arelle/archive/plugin/validate/XFsyntax/__init__.py +0 -64
  176. arelle/archive/plugin/validate/XFsyntax/xf.py +0 -2227
  177. arelle/archive/plugin/validate/calc2.py +0 -536
  178. arelle/archive/plugin/validateSchemaLxml.py +0 -156
  179. arelle/archive/plugin/validateTableInfoset.py +0 -52
  180. arelle/archive/us-gaap-dei-docType-extraction-frm.xml +0 -90
  181. arelle/archive/us-gaap-dei-ratio-cash-frm.xml +0 -150
  182. arelle/examples/plugin/formulaSuiteConverter.py +0 -212
  183. arelle/examples/plugin/functionsCustom.py +0 -59
  184. arelle/examples/plugin/hello_dolly.py +0 -64
  185. arelle/examples/plugin/multi.py +0 -58
  186. arelle/examples/plugin/rssSaveOim.py +0 -96
  187. arelle/examples/plugin/validate/XYZ/DisclosureSystems.py +0 -2
  188. arelle/examples/plugin/validate/XYZ/PluginValidationDataExtension.py +0 -10
  189. arelle/examples/plugin/validate/XYZ/ValidationPluginExtension.py +0 -49
  190. arelle/examples/plugin/validate/XYZ/__init__.py +0 -75
  191. arelle/examples/plugin/validate/XYZ/resources/config.xml +0 -16
  192. arelle/examples/plugin/validate/XYZ/rules/__init__.py +0 -0
  193. arelle/examples/plugin/validate/XYZ/rules/rules01.py +0 -110
  194. arelle/examples/plugin/validate/XYZ/rules/rules02.py +0 -59
  195. arelle/model/CommentBase.py +0 -9
  196. arelle/model/ElementBase.py +0 -11
  197. arelle/model/PIBase.py +0 -10
  198. arelle/model/__init__.py +0 -15
  199. arelle/scripts-macOS/startWebServer.command +0 -3
  200. arelle/scripts-unix/startWebServer.sh +0 -1
  201. arelle/scripts-windows/startWebServer.bat +0 -5
  202. {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/WHEEL +0 -0
  203. {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/entry_points.txt +0 -0
  204. {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
- from filelock import FileLock, Timeout
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
- # Attempt to load the default CA certificates from the OS using truststore if available, else fallback to OpenSSL's default context.
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
- urlScheme, schemeSep, urlSchemeSpecificPart = url.partition("://")
571
- urlPath, querySep, query = urlSchemeSpecificPart.partition("?")
572
- # RFC 3986: https://www.ietf.org/rfc/rfc3986.txt
573
- querySafeChars = ';/?'
574
- pathSafeChars = querySafeChars + ':@&=+$,'
575
- quotedUrlPath = quote(urlPath, safe=pathSafeChars)
576
- quotedQuery = quote(query, safe=querySafeChars)
577
- return urlScheme + schemeSep + quotedUrlPath + querySep + quotedQuery
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
- # 2022-09-15: assuming n, v are always strings
289
- s.append(' {0}="{1}"'.format(qname(elt, cast(str, n)),
290
- cast(str, v).replace("&","&amp;").replace('"', '&quot;')))
288
+ s.append(' {0}="{1}"'.format(qname(elt, n),
289
+ v.replace("&","&amp;").replace('"', '&quot;')))
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(cast(ModelObject, _child))
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(cast(ModelObject, child))
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: ModelObject, commentText: str) -> None:
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: ModelObject,
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
- # 2022-09-16: for some reason prefix is encouraged to always be a str in lxml-stubs,
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}) # type: ignore[dict-item] # above note
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(cast(ModelObject, child))
936
+ value = text(child)
943
937
  if qnames:
944
- _value = prefixedNameToClarkNotation(cast(ModelObject, child), value)
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
- ns, sep, localName = node.tag.partition('}')
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 = cast(str, aTag).partition('}')
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] = cast(str, aValue)
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 attrTag_, attrValue_ in elt.items():
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: # allow empty strings to be valid anyURIs
462
- if UrlUtil.isValidUriReference(value) is None:
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) # type: ignore[attr-defined]
707
- return self.resolve_empty(context) # type: ignore[attr-defined]
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: # type: ignore[attr-defined]
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__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
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.37.46'
21
- __version_tuple__ = version_tuple = (2, 37, 46)
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) -> Any:
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) # type: ignore[arg-type]
57
+ testcaseElement = etree.Element("testcase", nsmap=TESTCASE_NAMESPACES_BY_PREFIX)
58
58
  document = ModelDocument.create(
59
59
  modelXbrl,
60
60
  ModelDocument.Type.TESTCASE,
@@ -781,11 +781,11 @@ class XPathContext:
781
781
  elif axis.endswith("-sibling"):
782
782
  if isinstance(node, ModelObject):
783
783
  targetNodes = [
784
- sibling # type: ignore[misc]
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 == "*") # type: ignore[attr-defined]
788
- and (localname == sibling.localName or localname == "*") # type: ignore[attr-defined]
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 = href.rpartition("_IXDS#?#")[2]
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 Counter, defaultdict
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
- topLevelDir
26
- for topLevelDir in PackageUtils.getPackageTopLevelDirectories(filesource)
27
- if any(f"{topLevelDir}/{path}" in packageEntries for path in Const.REPORT_PACKAGE_PATHS)
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 any(entry.startswith(f"{stld}/{Const.REPORTS_DIRECTORY}") for entry in entries):
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
- if reportPackageJsonFile is None and reports is None:
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
- reportEntriesBySubDir = Counter(report.dir for report in reports or [] if not report.isTopLevel)
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
- inlineTarget = getattr(options, "inlineTarget", None)
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
- MULTI_TARGET_DISCLOSURE_SYSTEMS = [
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 ModelFact, ModelContext
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.regex.Pattern[str]
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: