arelle-release 2.17.1__py3-none-any.whl → 2.37.71__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 (893) hide show
  1. arelle/Aspect.py +6 -3
  2. arelle/BetaFeatures.py +3 -0
  3. arelle/Cntlr.py +117 -413
  4. arelle/CntlrCmdLine.py +364 -227
  5. arelle/CntlrQuickBooks.py +4 -2
  6. arelle/CntlrWebMain.py +179 -119
  7. arelle/CntlrWinMain.py +342 -124
  8. arelle/DialogAbout.py +1 -1
  9. arelle/DialogArcroleGroup.py +1 -1
  10. arelle/DialogFind.py +1 -1
  11. arelle/DialogFormulaParameters.py +2 -2
  12. arelle/DialogLanguage.py +45 -36
  13. arelle/DialogNewFactItem.py +1 -1
  14. arelle/DialogOpenArchive.py +30 -34
  15. arelle/DialogPackageManager.py +11 -8
  16. arelle/DialogPluginManager.py +43 -89
  17. arelle/DialogRssWatch.py +2 -2
  18. arelle/DialogURL.py +1 -1
  19. arelle/DialogUserPassword.py +1 -1
  20. arelle/DisclosureSystem.py +69 -1
  21. arelle/ErrorManager.py +321 -0
  22. arelle/FileSource.py +201 -99
  23. arelle/FunctionFn.py +44 -5
  24. arelle/FunctionIxt.py +16 -13
  25. arelle/FunctionUtil.py +1 -1
  26. arelle/FunctionXfi.py +68 -24
  27. arelle/FunctionXs.py +1 -1
  28. arelle/HtmlUtil.py +5 -4
  29. arelle/LeiUtil.py +63 -43
  30. arelle/LinkbaseType.py +94 -0
  31. arelle/LocalViewer.py +8 -2
  32. arelle/Locale.py +239 -79
  33. arelle/ModelDocument.py +180 -48
  34. arelle/ModelDtsObject.py +32 -27
  35. arelle/ModelFormulaObject.py +14 -6
  36. arelle/ModelInstanceObject.py +43 -14
  37. arelle/ModelManager.py +6 -1
  38. arelle/ModelObject.py +12 -8
  39. arelle/ModelObjectFactory.py +18 -2
  40. arelle/ModelRelationshipSet.py +46 -3
  41. arelle/ModelRenderingObject.py +899 -951
  42. arelle/ModelRssItem.py +2 -4
  43. arelle/ModelTestcaseObject.py +41 -4
  44. arelle/ModelValue.py +42 -14
  45. arelle/ModelVersReport.py +1 -1
  46. arelle/ModelXbrl.py +133 -273
  47. arelle/PackageManager.py +202 -176
  48. arelle/PluginManager.py +551 -239
  49. arelle/PluginUtils.py +54 -0
  50. arelle/PrototypeInstanceObject.py +53 -12
  51. arelle/PythonUtil.py +166 -25
  52. arelle/RuntimeOptions.py +32 -18
  53. arelle/SocketUtils.py +3 -0
  54. arelle/SystemInfo.py +1 -1
  55. arelle/TkTableWrapper.py +33 -5
  56. arelle/UITkTable.py +27 -21
  57. arelle/Updater.py +7 -3
  58. arelle/UrlUtil.py +6 -2
  59. arelle/Validate.py +596 -402
  60. arelle/ValidateDuplicateFacts.py +584 -0
  61. arelle/ValidateFileSource.py +38 -0
  62. arelle/ValidateFilingText.py +46 -29
  63. arelle/ValidateInfoset.py +104 -32
  64. arelle/ValidateUtr.py +31 -4
  65. arelle/ValidateXbrl.py +144 -120
  66. arelle/ValidateXbrlCalcs.py +51 -66
  67. arelle/ValidateXbrlDTS.py +98 -29
  68. arelle/Version.py +2 -7
  69. arelle/ViewFile.py +2 -0
  70. arelle/ViewFileDTS.py +7 -2
  71. arelle/ViewFileFactList.py +1 -1
  72. arelle/ViewFileFactTable.py +4 -4
  73. arelle/ViewFileRelationshipSet.py +36 -19
  74. arelle/ViewFileRenderedGrid.py +164 -753
  75. arelle/ViewFileRenderedLayout.py +174 -0
  76. arelle/ViewFileRenderedStructure.py +108 -0
  77. arelle/ViewWinDTS.py +4 -1
  78. arelle/ViewWinFactList.py +1 -1
  79. arelle/ViewWinFactTable.py +1 -1
  80. arelle/ViewWinRelationshipSet.py +14 -8
  81. arelle/ViewWinRenderedGrid.py +397 -287
  82. arelle/ViewWinRssFeed.py +4 -0
  83. arelle/ViewWinTree.py +15 -9
  84. arelle/ViewWinXml.py +1 -1
  85. arelle/WebCache.py +510 -272
  86. arelle/XbrlConst.py +202 -196
  87. arelle/XbrlUtil.py +2 -1
  88. arelle/XhtmlValidate.py +9 -23
  89. arelle/XmlUtil.py +24 -19
  90. arelle/XmlValidate.py +95 -67
  91. arelle/XmlValidateParticles.py +4 -4
  92. arelle/_version.py +33 -3
  93. arelle/api/Session.py +183 -0
  94. arelle/config/creationSoftwareNames.json +24 -10
  95. arelle/config/disclosuresystems.xml +1 -1
  96. arelle/config/disclosuresystems.xsd +3 -0
  97. arelle/config/sbr-text-formatting.xsd +737 -0
  98. arelle/conformance/CSVTestcaseLoader.py +102 -0
  99. arelle/formula/FactAspectsCache.py +10 -4
  100. arelle/formula/ValidateFormula.py +82 -194
  101. arelle/formula/XPathContext.py +42 -28
  102. arelle/formula/XPathParser.py +15 -9
  103. arelle/locale/ar_EG/LC_MESSAGES/ar_EG.po +3 -4
  104. arelle/locale/messages.pot +1 -2
  105. arelle/locale/ru/LC_MESSAGES/ru.po +2 -2
  106. arelle/logging/formatters/LogFormatter.py +47 -0
  107. arelle/logging/handlers/LogHandlerWithXml.py +94 -0
  108. arelle/logging/handlers/LogToBufferHandler.py +20 -0
  109. arelle/logging/handlers/LogToPrintHandler.py +41 -0
  110. arelle/logging/handlers/LogToXmlHandler.py +244 -0
  111. arelle/logging/handlers/StructuredMessageLogHandler.py +74 -0
  112. arelle/model/CommentBase.py +3 -0
  113. arelle/model/ElementBase.py +3 -0
  114. arelle/model/PIBase.py +3 -0
  115. arelle/model/__init__.py +3 -0
  116. arelle/oim/Load.py +2869 -0
  117. arelle/oim/Validate.py +155 -0
  118. arelle/oim/xml/Save.py +21 -0
  119. arelle/packages/PackageConst.py +7 -0
  120. arelle/packages/PackageType.py +13 -0
  121. arelle/packages/PackageUtils.py +22 -0
  122. arelle/packages/PackageValidation.py +200 -0
  123. arelle/packages/report/DetectReportPackage.py +13 -0
  124. arelle/packages/report/ReportPackage.py +265 -0
  125. arelle/packages/report/ReportPackageConst.py +79 -0
  126. arelle/packages/report/ReportPackageValidator.py +207 -0
  127. arelle/plugin/EdgarRendererAllReports.py +12 -12
  128. arelle/plugin/OimTaxonomy/ModelValueMore.py +15 -0
  129. arelle/plugin/OimTaxonomy/ValidateDTS.py +484 -0
  130. arelle/plugin/OimTaxonomy/ViewXbrlTxmyObj.py +239 -0
  131. arelle/plugin/OimTaxonomy/XbrlAbstract.py +16 -0
  132. arelle/plugin/OimTaxonomy/XbrlConcept.py +68 -0
  133. arelle/plugin/OimTaxonomy/XbrlConst.py +261 -0
  134. arelle/plugin/OimTaxonomy/XbrlCube.py +91 -0
  135. arelle/plugin/OimTaxonomy/XbrlDimension.py +38 -0
  136. arelle/plugin/OimTaxonomy/XbrlDts.py +152 -0
  137. arelle/plugin/OimTaxonomy/XbrlEntity.py +16 -0
  138. arelle/plugin/OimTaxonomy/XbrlGroup.py +22 -0
  139. arelle/plugin/OimTaxonomy/XbrlImportedTaxonomy.py +22 -0
  140. arelle/plugin/OimTaxonomy/XbrlLabel.py +31 -0
  141. arelle/plugin/OimTaxonomy/XbrlNetwork.py +100 -0
  142. arelle/plugin/OimTaxonomy/XbrlProperty.py +28 -0
  143. arelle/plugin/OimTaxonomy/XbrlReference.py +33 -0
  144. arelle/plugin/OimTaxonomy/XbrlReport.py +24 -0
  145. arelle/plugin/OimTaxonomy/XbrlTableTemplate.py +35 -0
  146. arelle/plugin/OimTaxonomy/XbrlTaxonomy.py +93 -0
  147. arelle/plugin/OimTaxonomy/XbrlTaxonomyObject.py +154 -0
  148. arelle/plugin/OimTaxonomy/XbrlTransform.py +17 -0
  149. arelle/plugin/OimTaxonomy/XbrlTypes.py +23 -0
  150. arelle/plugin/OimTaxonomy/XbrlUnit.py +17 -0
  151. arelle/plugin/OimTaxonomy/__init__.py +1037 -0
  152. arelle/plugin/OimTaxonomy/resources/iso4217.json +4479 -0
  153. arelle/plugin/OimTaxonomy/resources/oim-taxonomy-schema.json +935 -0
  154. arelle/plugin/OimTaxonomy/resources/ref.json +333 -0
  155. arelle/plugin/OimTaxonomy/resources/transform-types.json +2481 -0
  156. arelle/plugin/OimTaxonomy/resources/types.json +727 -0
  157. arelle/plugin/OimTaxonomy/resources/utr.json +3046 -0
  158. arelle/plugin/OimTaxonomy/resources/xbrlSpec.json +1082 -0
  159. arelle/plugin/formulaLoader.py +3 -3
  160. arelle/plugin/formulaSaver.py +4 -4
  161. arelle/plugin/inlineXbrlDocumentSet.py +331 -102
  162. arelle/plugin/internet/proxyNTLM/HTTPNtlmAuthHandler.py +1 -1
  163. arelle/plugin/loadFromExcel.py +13 -10
  164. arelle/plugin/loadFromOIM.py +16 -3096
  165. arelle/plugin/logging/saveMessages.py +1 -1
  166. arelle/plugin/saveHtmlEBAtables.py +293 -213
  167. arelle/plugin/saveLoadableOIM.py +652 -361
  168. arelle/plugin/saveOIMTaxonomy.py +311 -0
  169. arelle/plugin/streamingExtensions.py +1 -1
  170. arelle/plugin/systemInfo.py +46 -0
  171. arelle/plugin/transforms/tester.py +4 -4
  172. arelle/plugin/validate/CIPC/Const.py +18 -0
  173. arelle/plugin/validate/CIPC/__init__.py +34 -13
  174. arelle/plugin/validate/DBA/DisclosureSystems.py +12 -0
  175. arelle/plugin/validate/DBA/PluginValidationDataExtension.py +165 -0
  176. arelle/plugin/validate/DBA/ValidationPluginExtension.py +545 -0
  177. arelle/plugin/validate/DBA/__init__.py +49 -0
  178. arelle/plugin/validate/DBA/resources/config.xml +21 -0
  179. arelle/plugin/validate/DBA/rules/__init__.py +323 -0
  180. arelle/plugin/validate/DBA/rules/fr.py +1377 -0
  181. arelle/plugin/validate/DBA/rules/tc.py +45 -0
  182. arelle/plugin/validate/DBA/rules/th.py +172 -0
  183. arelle/plugin/validate/DBA/rules/tm.py +351 -0
  184. arelle/plugin/validate/DBA/rules/tr.py +373 -0
  185. arelle/plugin/validate/EBA/__init__.py +11 -12
  186. arelle/plugin/validate/EDINET/Constants.py +208 -0
  187. arelle/plugin/validate/EDINET/ContextRequirement.py +58 -0
  188. arelle/plugin/validate/EDINET/ControllerPluginData.py +298 -0
  189. arelle/plugin/validate/EDINET/CoverItemRequirements.py +42 -0
  190. arelle/plugin/validate/EDINET/DeiRequirements.py +118 -0
  191. arelle/plugin/validate/EDINET/DisclosureSystems.py +1 -0
  192. arelle/plugin/validate/EDINET/FilingFormat.py +275 -0
  193. arelle/plugin/validate/EDINET/FormType.py +134 -0
  194. arelle/plugin/validate/EDINET/ManifestInstance.py +236 -0
  195. arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +640 -0
  196. arelle/plugin/validate/EDINET/ReportFolderType.py +162 -0
  197. arelle/plugin/validate/EDINET/Statement.py +139 -0
  198. arelle/plugin/validate/EDINET/TableOfContentsBuilder.py +493 -0
  199. arelle/plugin/validate/EDINET/UploadContents.py +48 -0
  200. arelle/plugin/validate/EDINET/ValidationPluginExtension.py +64 -0
  201. arelle/plugin/validate/EDINET/__init__.py +109 -0
  202. arelle/plugin/validate/EDINET/resources/config.xml +22 -0
  203. arelle/plugin/validate/EDINET/resources/cover-item-requirements.json +793 -0
  204. arelle/plugin/validate/EDINET/resources/dei-requirements.csv +27 -0
  205. arelle/plugin/validate/EDINET/resources/edinet-taxonomies.xml +62 -0
  206. arelle/plugin/validate/EDINET/rules/contexts.py +547 -0
  207. arelle/plugin/validate/EDINET/rules/edinet.py +1991 -0
  208. arelle/plugin/validate/EDINET/rules/frta.py +301 -0
  209. arelle/plugin/validate/EDINET/rules/gfm.py +2394 -0
  210. arelle/plugin/validate/EDINET/rules/manifests.py +88 -0
  211. arelle/plugin/validate/EDINET/rules/upload.py +1370 -0
  212. arelle/plugin/validate/ESEF/Const.py +16 -75
  213. arelle/plugin/validate/ESEF/Dimensions.py +2 -2
  214. arelle/plugin/validate/ESEF/ESEF_2021/DTS.py +6 -1
  215. arelle/plugin/validate/ESEF/ESEF_2021/Image.py +7 -4
  216. arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py +80 -57
  217. arelle/plugin/validate/ESEF/ESEF_Current/DTS.py +60 -22
  218. arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py +272 -133
  219. arelle/plugin/validate/ESEF/Util.py +5 -19
  220. arelle/plugin/validate/ESEF/__init__.py +61 -46
  221. arelle/plugin/validate/ESEF/resources/authority-validations.json +120 -10
  222. arelle/plugin/validate/ESEF/resources/config.xml +44 -3
  223. arelle/plugin/validate/FERC/__init__.py +31 -18
  224. arelle/plugin/validate/FERC/config.xml +18 -18
  225. arelle/plugin/validate/NL/DisclosureSystems.py +19 -3
  226. arelle/plugin/validate/NL/PluginValidationDataExtension.py +710 -7
  227. arelle/plugin/validate/NL/ValidationPluginExtension.py +117 -12
  228. arelle/plugin/validate/NL/__init__.py +21 -10
  229. arelle/plugin/validate/NL/resources/config.xml +27 -6
  230. arelle/plugin/validate/NL/rules/br_kvk.py +81 -21
  231. arelle/plugin/validate/NL/rules/fg_nl.py +292 -0
  232. arelle/plugin/validate/NL/rules/fr_kvk.py +60 -7
  233. arelle/plugin/validate/NL/rules/fr_nl.py +705 -24
  234. arelle/plugin/validate/NL/rules/nl_kvk.py +2182 -0
  235. arelle/plugin/validate/ROS/DisclosureSystems.py +1 -0
  236. arelle/plugin/validate/ROS/PluginValidationDataExtension.py +109 -0
  237. arelle/plugin/validate/ROS/ValidationPluginExtension.py +27 -0
  238. arelle/plugin/validate/ROS/__init__.py +28 -341
  239. arelle/plugin/validate/ROS/resources/config.xml +20 -0
  240. arelle/plugin/validate/ROS/rules/__init__.py +56 -0
  241. arelle/plugin/validate/ROS/rules/ros.py +393 -0
  242. arelle/plugin/validate/UK/ValidateUK.py +1372 -0
  243. arelle/plugin/validate/{HMRC → UK}/__init__.py +195 -189
  244. arelle/plugin/validate/{HMRC → UK}/config.xml +1 -1
  245. arelle/plugin/xbrlDB/SqlDb.py +1 -1
  246. arelle/plugin/xbrlDB/XbrlOpenSqlDB.py +5 -5
  247. arelle/plugin/xbrlDB/XbrlPublicPostgresDB.py +1 -1
  248. arelle/plugin/xbrlDB/XbrlSemanticJsonDB.py +1 -1
  249. arelle/plugin/xbrlDB/XbrlSemanticRdfDB.py +1 -1
  250. arelle/plugin/xbrlDB/__init__.py +4 -1
  251. arelle/{RenderingEvaluator.py → rendering/RenderingEvaluator.py} +120 -99
  252. arelle/rendering/RenderingLayout.py +476 -0
  253. arelle/rendering/RenderingResolution.py +814 -0
  254. arelle/resources/cache/http/www.eurofiling.info/eu/fr/xbrl/ext/filing-indicators.xsd +20 -0
  255. arelle/resources/cache/http/www.w3.org/2001/03/xml.xsd +117 -0
  256. arelle/resources/cache/http/www.w3.org/2001/XMLSchema.xsd +2534 -0
  257. arelle/resources/cache/http/www.w3.org/2001/xml.xsd +287 -0
  258. arelle/resources/cache/http/www.xbrl.org/2003/xbrl-instance-2003-12-31.xsd +779 -0
  259. arelle/resources/cache/http/www.xbrl.org/2003/xbrl-linkbase-2003-12-31.xsd +486 -0
  260. arelle/resources/cache/http/www.xbrl.org/2003/xl-2003-12-31.xsd +251 -0
  261. arelle/resources/cache/http/www.xbrl.org/2003/xlink-2003-12-31.xsd +121 -0
  262. arelle/resources/cache/http/www.xbrl.org/2004/ref-2004-08-10.xsd +129 -0
  263. arelle/resources/cache/http/www.xbrl.org/2005/xbrldt-2005.xsd +53 -0
  264. arelle/resources/cache/http/www.xbrl.org/2006/ref-2006-02-27.xsd +120 -0
  265. arelle/resources/cache/http/www.xbrl.org/2006/xbrldi-2006.xsd +41 -0
  266. arelle/resources/cache/http/www.xbrl.org/2008/boolean-filter.xsd +51 -0
  267. arelle/resources/cache/http/www.xbrl.org/2008/concept-filter.xsd +127 -0
  268. arelle/resources/cache/http/www.xbrl.org/2008/conformance.xsd +116 -0
  269. arelle/resources/cache/http/www.xbrl.org/2008/conformanceFunction.xsd +51 -0
  270. arelle/resources/cache/http/www.xbrl.org/2008/consistency-assertion.xsd +66 -0
  271. arelle/resources/cache/http/www.xbrl.org/2008/dimension-filter.xsd +86 -0
  272. arelle/resources/cache/http/www.xbrl.org/2008/entity-filter.xsd +92 -0
  273. arelle/resources/cache/http/www.xbrl.org/2008/existence-assertion.xsd +44 -0
  274. arelle/resources/cache/http/www.xbrl.org/2008/formula.xsd +261 -0
  275. arelle/resources/cache/http/www.xbrl.org/2008/function.xsd +90 -0
  276. arelle/resources/cache/http/www.xbrl.org/2008/general-filter.xsd +38 -0
  277. arelle/resources/cache/http/www.xbrl.org/2008/generic-label.xsd +80 -0
  278. arelle/resources/cache/http/www.xbrl.org/2008/generic-link.xsd +81 -0
  279. arelle/resources/cache/http/www.xbrl.org/2008/generic-reference.xsd +63 -0
  280. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xbrl/xbrl-instance-2003-12-31-ixmod.xsd +788 -0
  281. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xbrl/xbrl-linkbase-2003-12-31-ixmod.xsd +488 -0
  282. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xbrl/xl-2003-12-31.xsd +248 -0
  283. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xbrl/xlink-2003-12-31.xsd +117 -0
  284. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xframes-1.xsd +166 -0
  285. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-applet-1.xsd +66 -0
  286. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-attribs-1.xsd +72 -0
  287. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-base-1.xsd +36 -0
  288. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-basic-form-1.xsd +195 -0
  289. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-basic-table-1.xsd +169 -0
  290. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-basic10-model-1.xsd +376 -0
  291. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-basic10-module-redefines-1.xsd +61 -0
  292. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-basic10-modules-1.xsd +259 -0
  293. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-basic10.xsd +98 -0
  294. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-bdo-1.xsd +78 -0
  295. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-blkphras-1.xsd +161 -0
  296. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-blkpres-1.xsd +37 -0
  297. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-blkstruct-1.xsd +49 -0
  298. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-charent-1.xsd +38 -0
  299. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-copyright-1.xsd +29 -0
  300. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-csismap-1.xsd +96 -0
  301. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-datatypes-1.xsd +128 -0
  302. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-edit-1.xsd +39 -0
  303. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-events-1.xsd +130 -0
  304. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-form-1.xsd +326 -0
  305. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-frames-1.xsd +113 -0
  306. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-framework-1.xsd +66 -0
  307. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-hypertext-1.xsd +47 -0
  308. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-iframe-1.xsd +68 -0
  309. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-image-1.xsd +45 -0
  310. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-inlphras-1.xsd +163 -0
  311. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-inlpres-1.xsd +39 -0
  312. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-inlstruct-1.xsd +50 -0
  313. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-inlstyle-1.xsd +27 -0
  314. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-legacy-1.xsd +97 -0
  315. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-link-1.xsd +45 -0
  316. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-list-1.xsd +99 -0
  317. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-meta-1.xsd +42 -0
  318. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-misc-1.xsd +441 -0
  319. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-nameident-1.xsd +63 -0
  320. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-notations-1.xsd +69 -0
  321. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-object-1.xsd +76 -0
  322. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-param-1.xsd +51 -0
  323. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-pres-1.xsd +51 -0
  324. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-ruby-1.xsd +171 -0
  325. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-ruby-basic-1.xsd +89 -0
  326. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-script-1.xsd +70 -0
  327. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-ssismap-1.xsd +43 -0
  328. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-struct-1.xsd +112 -0
  329. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-style-1.xsd +52 -0
  330. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-table-1.xsd +272 -0
  331. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-target-1.xsd +53 -0
  332. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml-text-1.xsd +67 -0
  333. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml11-model-1.xsd +677 -0
  334. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml11-module-redefines-1.xsd +335 -0
  335. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml11-modules-1.xsd +528 -0
  336. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml11.xsd +104 -0
  337. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xhtml2.xsd +21 -0
  338. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xml-events-1.xsd +73 -0
  339. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xml-events-2.xsd +74 -0
  340. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xml-events-attribs-1.xsd +73 -0
  341. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xml-events-attribs-2.xsd +75 -0
  342. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xml-events-copyright-1.xsd +34 -0
  343. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xml-events-copyright-2.xsd +34 -0
  344. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml/xml-handlers-2.xsd +98 -0
  345. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml-inlinexbrl-1_0-definitions.xsd +225 -0
  346. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml-inlinexbrl-1_0-model.xsd +681 -0
  347. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml-inlinexbrl-1_0-modules.xsd +535 -0
  348. arelle/resources/cache/http/www.xbrl.org/2008/inlinexbrl/xhtml-inlinexbrl-1_0.xsd +40 -0
  349. arelle/resources/cache/http/www.xbrl.org/2008/match-filter.xsd +94 -0
  350. arelle/resources/cache/http/www.xbrl.org/2008/period-filter.xsd +86 -0
  351. arelle/resources/cache/http/www.xbrl.org/2008/registry.xsd +145 -0
  352. arelle/resources/cache/http/www.xbrl.org/2008/relative-filter.xsd +38 -0
  353. arelle/resources/cache/http/www.xbrl.org/2008/segment-scenario-filter.xsd +41 -0
  354. arelle/resources/cache/http/www.xbrl.org/2008/tuple-filter.xsd +83 -0
  355. arelle/resources/cache/http/www.xbrl.org/2008/unit-filter.xsd +58 -0
  356. arelle/resources/cache/http/www.xbrl.org/2008/validation.xsd +78 -0
  357. arelle/resources/cache/http/www.xbrl.org/2008/value-assertion.xsd +43 -0
  358. arelle/resources/cache/http/www.xbrl.org/2008/value-filter.xsd +43 -0
  359. arelle/resources/cache/http/www.xbrl.org/2008/variable.xsd +240 -0
  360. arelle/resources/cache/http/www.xbrl.org/2010/aspect-cover-filter.xsd +67 -0
  361. arelle/resources/cache/http/www.xbrl.org/2010/concept-relation-filter.xsd +108 -0
  362. arelle/resources/cache/http/www.xbrl.org/2010/custom-function-implementation.xsd +71 -0
  363. arelle/resources/cache/http/www.xbrl.org/2010/generic-message.xsd +68 -0
  364. arelle/resources/cache/http/www.xbrl.org/2010/validation-message.xsd +50 -0
  365. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xbrl/xbrl-instance-2003-12-31-ixmod.xsd +788 -0
  366. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xbrl/xbrl-linkbase-2003-12-31-ixmod.xsd +488 -0
  367. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xbrl/xl-2003-12-31.xsd +248 -0
  368. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xbrl/xlink-2003-12-31.xsd +117 -0
  369. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xframes-1.xsd +166 -0
  370. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-applet-1.xsd +66 -0
  371. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-attribs-1.xsd +72 -0
  372. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-base-1.xsd +36 -0
  373. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-basic-form-1.xsd +195 -0
  374. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-basic-table-1.xsd +169 -0
  375. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-basic10-model-1.xsd +376 -0
  376. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-basic10-module-redefines-1.xsd +61 -0
  377. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-basic10-modules-1.xsd +259 -0
  378. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-basic10.xsd +98 -0
  379. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-bdo-1.xsd +78 -0
  380. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-blkphras-1.xsd +161 -0
  381. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-blkpres-1.xsd +37 -0
  382. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-blkstruct-1.xsd +49 -0
  383. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-charent-1.xsd +38 -0
  384. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-copyright-1.xsd +29 -0
  385. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-csismap-1.xsd +96 -0
  386. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-datatypes-1.xsd +128 -0
  387. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-edit-1.xsd +39 -0
  388. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-events-1.xsd +130 -0
  389. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-form-1.xsd +326 -0
  390. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-frames-1.xsd +113 -0
  391. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-framework-1.xsd +66 -0
  392. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-hypertext-1.xsd +47 -0
  393. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-iframe-1.xsd +68 -0
  394. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-image-1.xsd +45 -0
  395. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-inlphras-1.xsd +163 -0
  396. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-inlpres-1.xsd +39 -0
  397. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-inlstruct-1.xsd +50 -0
  398. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-inlstyle-1.xsd +27 -0
  399. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-legacy-1.xsd +97 -0
  400. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-link-1.xsd +45 -0
  401. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-list-1.xsd +99 -0
  402. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-meta-1.xsd +42 -0
  403. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-misc-1.xsd +441 -0
  404. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-nameident-1.xsd +63 -0
  405. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-notations-1.xsd +69 -0
  406. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-object-1.xsd +76 -0
  407. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-param-1.xsd +51 -0
  408. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-pres-1.xsd +51 -0
  409. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-ruby-1.xsd +171 -0
  410. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-ruby-basic-1.xsd +89 -0
  411. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-script-1.xsd +70 -0
  412. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-ssismap-1.xsd +43 -0
  413. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-struct-1.xsd +112 -0
  414. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-style-1.xsd +52 -0
  415. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-table-1.xsd +272 -0
  416. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-target-1.xsd +53 -0
  417. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml-text-1.xsd +67 -0
  418. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml11-model-1.xsd +677 -0
  419. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml11-module-redefines-1.xsd +335 -0
  420. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml11-modules-1.xsd +528 -0
  421. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml11.xsd +104 -0
  422. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xhtml2.xsd +21 -0
  423. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xml-events-1.xsd +73 -0
  424. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xml-events-2.xsd +74 -0
  425. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xml-events-attribs-1.xsd +73 -0
  426. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xml-events-attribs-2.xsd +75 -0
  427. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xml-events-copyright-1.xsd +34 -0
  428. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xml-events-copyright-2.xsd +34 -0
  429. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml/xml-handlers-2.xsd +98 -0
  430. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml-inlinexbrl-1_1-definitions.xsd +252 -0
  431. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml-inlinexbrl-1_1-model.xsd +681 -0
  432. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml-inlinexbrl-1_1-modules.xsd +535 -0
  433. arelle/resources/cache/http/www.xbrl.org/2013/inlineXBRL/xhtml-inlinexbrl-1_1.xsd +40 -0
  434. arelle/resources/cache/http/www.xbrl.org/2013/match-filter.xsd +94 -0
  435. arelle/resources/cache/http/www.xbrl.org/2013/preferred-label.xsd +12 -0
  436. arelle/resources/cache/http/www.xbrl.org/2013/versioning-base.xsd +142 -0
  437. arelle/resources/cache/http/www.xbrl.org/2013/versioning-concept-details.xsd +143 -0
  438. arelle/resources/cache/http/www.xbrl.org/2013/versioning-concept-use.xsd +64 -0
  439. arelle/resources/cache/http/www.xbrl.org/2013/versioning-dimensions.xsd +162 -0
  440. arelle/resources/cache/http/www.xbrl.org/2014/extensible-enumerations.xsd +27 -0
  441. arelle/resources/cache/http/www.xbrl.org/2014/table.xsd +356 -0
  442. arelle/resources/cache/http/www.xbrl.org/2014/tablemodel.xsd +156 -0
  443. arelle/resources/cache/http/www.xbrl.org/2016/assertion-severity.xsd +29 -0
  444. arelle/resources/cache/http/www.xbrl.org/2016/severities.xml +21 -0
  445. arelle/resources/cache/http/www.xbrl.org/2016/taxonomy-package-catalog.xsd +38 -0
  446. arelle/resources/cache/http/www.xbrl.org/2016/taxonomy-package.xsd +154 -0
  447. arelle/resources/cache/http/www.xbrl.org/2022/assertion-severity.xsd +43 -0
  448. arelle/resources/cache/http/www.xbrl.org/2022/severities.xml +21 -0
  449. arelle/resources/cache/http/www.xbrl.org/dtr/type/nonNumeric-2009-12-16.xsd +76 -0
  450. arelle/resources/cache/http/www.xbrl.org/dtr/type/numeric-2009-12-16.xsd +78 -0
  451. arelle/resources/cache/http/www.xbrl.org/lrr/arcrole/accounting-arcrole-2023-01-04.xsd +39 -0
  452. arelle/resources/cache/http/www.xbrl.org/lrr/arcrole/deprecated-2009-12-16.xsd +29 -0
  453. arelle/resources/cache/http/www.xbrl.org/lrr/arcrole/esma-arcrole-2018-11-21.xsd +14 -0
  454. arelle/resources/cache/http/www.xbrl.org/lrr/arcrole/factExplanatory-2009-12-16.xsd +13 -0
  455. arelle/resources/cache/http/www.xbrl.org/lrr/arcrole/jpfr-arcrole-2007-11-07.xsd +27 -0
  456. arelle/resources/cache/http/www.xbrl.org/lrr/arcrole/parent-child-2013-09-19.xsd +12 -0
  457. arelle/resources/cache/http/www.xbrl.org/lrr/role/deprecated-2009-12-16.xsd +17 -0
  458. arelle/resources/cache/http/www.xbrl.org/lrr/role/jpfr-role-2007-11-07.xsd +47 -0
  459. arelle/resources/cache/http/www.xbrl.org/lrr/role/negated-2008-03-31.xsd +30 -0
  460. arelle/resources/cache/http/www.xbrl.org/lrr/role/negated-2009-12-16.xsd +33 -0
  461. arelle/resources/cache/http/www.xbrl.org/lrr/role/negative-2009-12-16.xsd +25 -0
  462. arelle/resources/cache/http/www.xbrl.org/lrr/role/net-2009-12-16.xsd +13 -0
  463. arelle/resources/cache/http/www.xbrl.org/lrr/role/positive-2009-12-16.xsd +25 -0
  464. arelle/resources/cache/http/www.xbrl.org/lrr/role/property-2022-09-28.xsd +15 -0
  465. arelle/resources/cache/http/www.xbrl.org/lrr/role/reference-2009-12-16.xsd +21 -0
  466. arelle/resources/cache/http/www.xbrl.org/lrr/role/restated-2006-02-21.xsd +19 -0
  467. arelle/resources/cache/http/www.xbrl.org/utr/2012-01-30/utr.xml +4543 -0
  468. arelle/resources/cache/http/www.xbrl.org/utr/2012-10-31/utr.xml +4510 -0
  469. arelle/resources/cache/http/www.xbrl.org/utr/2012-11-30/utr.xml +4567 -0
  470. arelle/resources/cache/http/www.xbrl.org/utr/2013-02-28/utr.xml +5180 -0
  471. arelle/resources/cache/http/www.xbrl.org/utr/2013-05-17/utr.xml +5349 -0
  472. arelle/resources/cache/http/www.xbrl.org/utr/2016-08-10/utr.xml +5363 -0
  473. arelle/resources/cache/http/www.xbrl.org/utr/2017-07-12/utr.xml +6164 -0
  474. arelle/resources/cache/http/www.xbrl.org/utr/2021-02-16/utr.xml +6370 -0
  475. arelle/resources/cache/http/www.xbrl.org/utr/2021-12-08/utr.xml +6493 -0
  476. arelle/resources/cache/http/www.xbrl.org/utr/2022-02-16/utr.xml +6551 -0
  477. arelle/resources/cache/http/www.xbrl.org/utr/2022-07-20/utr.xml +6638 -0
  478. arelle/resources/cache/http/www.xbrl.org/utr/2023-12-20/utr.xml +6680 -0
  479. arelle/resources/cache/http/www.xbrl.org/utr/2024-01-31/utr.xml +6680 -0
  480. arelle/resources/cache/http/www.xbrl.org/utr/2024-10-22/utr.xml +6693 -0
  481. arelle/resources/cache/http/www.xbrl.org/utr/utr.xml +6693 -0
  482. arelle/resources/cache/https/www.xbrl.org/2005/conformance.xsd +87 -0
  483. arelle/resources/cache/https/www.xbrl.org/2020/extensible-enumerations-2.0.xsd +51 -0
  484. arelle/resources/cache/https/www.xbrl.org/2023/calculation-1.1.xsd +27 -0
  485. arelle/resources/cache/https/www.xbrl.org/dtr/type/2020-01-21/types.xsd +812 -0
  486. arelle/resources/cache/https/www.xbrl.org/dtr/type/2022-03-31/types.xsd +847 -0
  487. arelle/resources/cache/https/www.xbrl.org/dtr/type/2024-01-31/types.xsd +897 -0
  488. arelle/resources/cache/https/www.xbrl.org/taxonomy/int/filing-indicators/REC/2021-02-03/filing-indicators-def.xml +68 -0
  489. arelle/resources/cache/https/www.xbrl.org/taxonomy/int/filing-indicators/REC/2021-02-03/filing-indicators-label.xml +84 -0
  490. arelle/resources/cache/https/www.xbrl.org/taxonomy/int/filing-indicators/REC/2021-02-03/filing-indicators.xsd +67 -0
  491. arelle/resources/libs/Tktable2.11/linux-x86_64/README.txt +149 -0
  492. arelle/resources/libs/Tktable2.11/linux-x86_64/html/tkTable.html +2039 -0
  493. arelle/resources/libs/Tktable2.11/linux-x86_64/libTktable2.11.so +0 -0
  494. arelle/resources/libs/Tktable2.11/linux-x86_64/license.txt +51 -0
  495. arelle/resources/libs/Tktable2.11/linux-x86_64/pkgIndex.tcl +3 -0
  496. arelle/resources/libs/Tktable2.11/linux-x86_64/tkTable.tcl +825 -0
  497. arelle/resources/libs/Tktable2.11/linux-x86_64/tktable.py +674 -0
  498. arelle/resources/libs/Tktable2.11/macos-arm64/README.txt +149 -0
  499. arelle/resources/libs/Tktable2.11/macos-arm64/html/tkTable.html +2039 -0
  500. arelle/resources/libs/Tktable2.11/macos-arm64/libTktable2.11.dylib +0 -0
  501. arelle/resources/libs/Tktable2.11/macos-arm64/license.txt +51 -0
  502. arelle/resources/libs/Tktable2.11/macos-arm64/pkgIndex.tcl +2 -0
  503. arelle/resources/libs/Tktable2.11/macos-arm64/tkTable.tcl +825 -0
  504. arelle/resources/libs/Tktable2.11/macos-arm64/tktable.py +674 -0
  505. arelle/resources/libs/Tktable2.11/macos-x86_64/README.txt +149 -0
  506. arelle/resources/libs/Tktable2.11/macos-x86_64/html/tkTable.html +2039 -0
  507. arelle/resources/libs/Tktable2.11/macos-x86_64/libTktable2.11.dylib +0 -0
  508. arelle/resources/libs/Tktable2.11/macos-x86_64/license.txt +51 -0
  509. arelle/resources/libs/Tktable2.11/macos-x86_64/pkgIndex.tcl +2 -0
  510. arelle/resources/libs/Tktable2.11/macos-x86_64/tkTable.tcl +825 -0
  511. arelle/resources/libs/Tktable2.11/macos-x86_64/tktable.py +674 -0
  512. arelle/resources/libs/Tktable2.11/win-x86_64/Tktable.dll +0 -0
  513. arelle/resources/libs/Tktable2.11/win-x86_64/pkgIndex.tcl +2 -0
  514. arelle/resources/libs/Tktable2.11/win-x86_64/tkTable.tcl +825 -0
  515. arelle/typing.py +9 -4
  516. arelle/utils/Contexts.py +38 -0
  517. arelle/utils/EntryPointDetection.py +139 -0
  518. arelle/utils/Equivalence.py +22 -0
  519. arelle/utils/{validate/PluginValidationData.py → PluginData.py} +5 -2
  520. arelle/utils/PluginHooks.py +256 -5
  521. arelle/utils/Units.py +36 -0
  522. arelle/utils/validate/Decorator.py +5 -3
  523. arelle/utils/validate/DetectScriptsInXhtml.py +99 -0
  524. arelle/utils/validate/ESEFImage.py +283 -0
  525. arelle/utils/validate/Validation.py +9 -1
  526. arelle/utils/validate/ValidationPlugin.py +74 -11
  527. arelle/utils/validate/ValidationUtil.py +55 -0
  528. arelle/webserver/bottle.py +5 -4424
  529. {arelle_release-2.17.1.dist-info → arelle_release-2.37.71.dist-info}/METADATA +51 -42
  530. arelle_release-2.37.71.dist-info/RECORD +697 -0
  531. {arelle_release-2.17.1.dist-info → arelle_release-2.37.71.dist-info}/WHEEL +1 -1
  532. {arelle_release-2.17.1.dist-info → arelle_release-2.37.71.dist-info/licenses}/LICENSE.md +1 -4
  533. {arelle_release-2.17.1.dist-info → arelle_release-2.37.71.dist-info}/top_level.txt +0 -1
  534. arelle/DialogOpenTaxonomyPackage.py +0 -1
  535. arelle/RenderingResolver.py +0 -624
  536. arelle/examples/.pydevproject +0 -5
  537. arelle/examples/CustomLogger.py +0 -43
  538. arelle/examples/LoadEFMvalidate.py +0 -32
  539. arelle/examples/LoadSavePreLbCsv.py +0 -26
  540. arelle/examples/LoadValidate.cs +0 -31
  541. arelle/examples/LoadValidate.py +0 -36
  542. arelle/examples/LoadValidateCmdLine.java +0 -69
  543. arelle/examples/LoadValidatePostedZip.java +0 -57
  544. arelle/examples/LoadValidateWebService.java +0 -34
  545. arelle/examples/SaveTableToExelle.py +0 -140
  546. arelle/examples/TR3toTR4.py +0 -88
  547. arelle/examples/plugin/bigInstance.py +0 -394
  548. arelle/examples/plugin/cmdWebServerExtension.py +0 -42
  549. arelle/examples/plugin/crashTest.py +0 -38
  550. arelle/examples/plugin/formulaSuiteConverter.py +0 -212
  551. arelle/examples/plugin/functionsCustom.py +0 -59
  552. arelle/examples/plugin/hello_dolly.py +0 -64
  553. arelle/examples/plugin/hello_i18n.pot +0 -26
  554. arelle/examples/plugin/hello_i18n.py +0 -32
  555. arelle/examples/plugin/importTestChild1.py +0 -21
  556. arelle/examples/plugin/importTestChild2.py +0 -22
  557. arelle/examples/plugin/importTestGrandchild1.py +0 -21
  558. arelle/examples/plugin/importTestGrandchild2.py +0 -21
  559. arelle/examples/plugin/importTestImported1.py +0 -23
  560. arelle/examples/plugin/importTestImported11.py +0 -22
  561. arelle/examples/plugin/importTestParent.py +0 -48
  562. arelle/examples/plugin/locale/fr/LC_MESSAGES/hello_i18n.po +0 -25
  563. arelle/examples/plugin/packagedImportTest/__init__.py +0 -47
  564. arelle/examples/plugin/packagedImportTest/importTestChild1.py +0 -21
  565. arelle/examples/plugin/packagedImportTest/importTestChild2.py +0 -22
  566. arelle/examples/plugin/packagedImportTest/importTestGrandchild1.py +0 -21
  567. arelle/examples/plugin/packagedImportTest/importTestGrandchild2.py +0 -21
  568. arelle/examples/plugin/packagedImportTest/importTestImported1.py +0 -24
  569. arelle/examples/plugin/packagedImportTest/importTestImported11.py +0 -21
  570. arelle/examples/plugin/packagedImportTest/subdir/importTestImported111.py +0 -21
  571. arelle/examples/plugin/packagedImportTest/subdir/subsubdir/importTestImported1111.py +0 -21
  572. arelle/examples/plugin/sakaCalendar.py +0 -215
  573. arelle/examples/plugin/saveInstanceInfoset.py +0 -121
  574. arelle/examples/plugin/streamingExtensions.py +0 -335
  575. arelle/examples/plugin/testcaseCalc11ValidateSetup.py +0 -32
  576. arelle/examples/plugin/testcaseIxExpectedHtmlFixup.py +0 -45
  577. arelle/examples/plugin/updateTableLB.py +0 -242
  578. arelle/examples/plugin/validate/XYZ/DisclosureSystems.py +0 -2
  579. arelle/examples/plugin/validate/XYZ/PluginValidationDataExtension.py +0 -10
  580. arelle/examples/plugin/validate/XYZ/ValidationPluginExtension.py +0 -49
  581. arelle/examples/plugin/validate/XYZ/__init__.py +0 -75
  582. arelle/examples/plugin/validate/XYZ/resources/config.xml +0 -16
  583. arelle/examples/plugin/validate/XYZ/rules/rules01.py +0 -109
  584. arelle/examples/plugin/validate/XYZ/rules/rules02.py +0 -58
  585. arelle/examples/plugin/validateSchemaLxml.py +0 -156
  586. arelle/examples/plugin/validateTableInfoset.py +0 -52
  587. arelle/examples/us-gaap-dei-docType-extraction-frm.xml +0 -90
  588. arelle/examples/us-gaap-dei-ratio-cash-frm.xml +0 -150
  589. arelle/plugin/functionsXmlCreation.py +0 -106
  590. arelle/plugin/instanceInfo.py +0 -306
  591. arelle/plugin/loadFromOIM-2018.py +0 -1282
  592. arelle/plugin/objectmaker.py +0 -285
  593. arelle/plugin/sphinx/FormulaGenerator.py +0 -823
  594. arelle/plugin/sphinx/SphinxContext.py +0 -404
  595. arelle/plugin/sphinx/SphinxEvaluator.py +0 -783
  596. arelle/plugin/sphinx/SphinxMethods.py +0 -1287
  597. arelle/plugin/sphinx/SphinxParser.py +0 -1093
  598. arelle/plugin/sphinx/SphinxValidator.py +0 -163
  599. arelle/plugin/sphinx/US-GAAP Ratios Example.xsr +0 -52
  600. arelle/plugin/sphinx/__init__.py +0 -285
  601. arelle/plugin/transforms/SEC/__init__.py +0 -308
  602. arelle/plugin/transforms/SEC/conf/README.md +0 -39
  603. arelle/plugin/transforms/SEC/conf/extractTestcase.sh +0 -2
  604. arelle/plugin/transforms/SEC/conf/extractTestcase.xsl +0 -109
  605. arelle/plugin/transforms/SEC/conf/runIxtSecTests.sh +0 -16
  606. arelle/plugin/transforms/SEC/conf/saxon9.jar +0 -0
  607. arelle/plugin/transforms/SEC/conf/testcase.xml +0 -7117
  608. arelle/plugin/transforms/SEC/conf/tests.xml +0 -848
  609. arelle/plugin/transforms/SEC/text2num.py +0 -110
  610. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-boolballotbox.xml +0 -66
  611. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-countrynameen.xml +0 -65
  612. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-datequarterend.xml +0 -66
  613. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-durday.xml +0 -61
  614. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-durhour.xml +0 -69
  615. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-durmonth.xml +0 -71
  616. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-durweek.xml +0 -70
  617. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-durwordsen.xml +0 -56
  618. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-duryear.xml +0 -64
  619. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-edgarprovcountryen.xml +0 -65
  620. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-entityfilercategoryen.xml +0 -63
  621. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-exchnameen.xml +0 -86
  622. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-numwordsen.xml +0 -55
  623. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-stateprovnameen.xml +0 -64
  624. arelle/plugin/transforms/SEC/transformationRegistry/registry/ixt-sec-yesnoballotbox.xml +0 -66
  625. arelle/plugin/transforms/SEC/transformationRegistry/registry/transform-registry.xml +0 -314
  626. arelle/plugin/transforms/SEC/transformationRegistry/schema/inlinexbrl-sec-transformation.xsd +0 -418
  627. arelle/plugin/validate/EFM/Consts.py +0 -362
  628. arelle/plugin/validate/EFM/DTS.py +0 -569
  629. arelle/plugin/validate/EFM/Dimensions.py +0 -264
  630. arelle/plugin/validate/EFM/Document.py +0 -206
  631. arelle/plugin/validate/EFM/Filing.py +0 -4383
  632. arelle/plugin/validate/EFM/IsolateSeparateIXDSes.py +0 -19
  633. arelle/plugin/validate/EFM/MessageNumericId.py +0 -142
  634. arelle/plugin/validate/EFM/PreCalAlignment.py +0 -324
  635. arelle/plugin/validate/EFM/Util.py +0 -688
  636. arelle/plugin/validate/EFM/__init__.py +0 -843
  637. arelle/plugin/validate/EFM/config.xml +0 -333
  638. arelle/plugin/validate/EFM/resources/README.md +0 -57
  639. arelle/plugin/validate/EFM/resources/axiswarnings.json +0 -27
  640. arelle/plugin/validate/EFM/resources/cef-deprecated-concepts.json +0 -8
  641. arelle/plugin/validate/EFM/resources/country-deprecated-concepts.json +0 -19
  642. arelle/plugin/validate/EFM/resources/currency-deprecated-concepts.json +0 -7
  643. arelle/plugin/validate/EFM/resources/dei-deprecated-concepts.json +0 -8
  644. arelle/plugin/validate/EFM/resources/dei-validations.json +0 -2884
  645. arelle/plugin/validate/EFM/resources/dqc-us-rules.json +0 -1389
  646. arelle/plugin/validate/EFM/resources/ecd-deprecated-concepts.json +0 -1
  647. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-16-4.xml +0 -115
  648. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-17-0-4.xml +0 -300
  649. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-17-1.xml +0 -304
  650. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-17-2.xml +0 -290
  651. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-17-3-1.xml +0 -294
  652. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-18.1.xml +0 -549
  653. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-18.2.xml +0 -506
  654. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-18.3.xml +0 -496
  655. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-19-1.xml +0 -662
  656. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-19-2.xml +0 -3761
  657. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-19-3.xml +0 -3577
  658. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-20-1.xml +0 -4020
  659. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-20-2.xml +0 -3320
  660. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-20-3.xml +0 -2998
  661. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-2012.xml +0 -957
  662. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-2013.xml +0 -982
  663. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-2014.xml +0 -1001
  664. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-2015.xml +0 -1076
  665. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-2016.xml +0 -120
  666. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-21-1.xml +0 -3329
  667. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-21-2.xml +0 -1230
  668. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-21-3.xml +0 -1113
  669. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-21-4.xml +0 -1321
  670. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-22-1-preview.xml +0 -1721
  671. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-22-1.xml +0 -1841
  672. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-22-2-2.xml +0 -1450
  673. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-22-2.xml +0 -1429
  674. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-22-4.xml +0 -1527
  675. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-23-1-1.xml +0 -2049
  676. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-23-1.xml +0 -2065
  677. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-23-2.xml +0 -1674
  678. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-23-3.xml +0 -1715
  679. arelle/plugin/validate/EFM/resources/edgartaxonomies/edgartaxonomies-all-years.xml +0 -10671
  680. arelle/plugin/validate/EFM/resources/edgartaxonomies/erxl.xsd +0 -69
  681. arelle/plugin/validate/EFM/resources/edgartaxonomies/extendedtaxonomies-all-years.xml +0 -18
  682. arelle/plugin/validate/EFM/resources/edgartaxonomies/ifrs-taxonomies.xml +0 -3126
  683. arelle/plugin/validate/EFM/resources/edgartaxonomies/ifrstaxonomies-all-years.xml +0 -22
  684. arelle/plugin/validate/EFM/resources/ex26-validations.json +0 -255
  685. arelle/plugin/validate/EFM/resources/exch-deprecated-concepts.json +0 -163
  686. arelle/plugin/validate/EFM/resources/ifrs-full-deprecated-concepts.json +0 -204
  687. arelle/plugin/validate/EFM/resources/invest-deprecated-concepts.json +0 -99
  688. arelle/plugin/validate/EFM/resources/ixbrl-transform-registries.json +0 -16
  689. arelle/plugin/validate/EFM/resources/naics-deprecated-concepts.json +0 -295
  690. arelle/plugin/validate/EFM/resources/oef-deprecated-concepts.json +0 -59
  691. arelle/plugin/validate/EFM/resources/other-standard-taxonomies.json +0 -12
  692. arelle/plugin/validate/EFM/resources/rr-deprecated-concepts.json +0 -14
  693. arelle/plugin/validate/EFM/resources/rxp-deprecated-concepts.json +0 -1
  694. arelle/plugin/validate/EFM/resources/shr-deprecated-concepts.json +0 -1
  695. arelle/plugin/validate/EFM/resources/sic-deprecated-concepts.json +0 -1
  696. arelle/plugin/validate/EFM/resources/signwarnings.json +0 -112
  697. arelle/plugin/validate/EFM/resources/srt-deprecated-concepts.json +0 -1
  698. arelle/plugin/validate/EFM/resources/stpr-deprecated-concepts.json +0 -1
  699. arelle/plugin/validate/EFM/resources/taxonomy-compatibility.json +0 -79
  700. arelle/plugin/validate/EFM/resources/us-gaap-deprecated-concepts.json +0 -2886
  701. arelle/plugin/validate/EFM/resources/us-gaap-rels-2020.json +0 -29068
  702. arelle/plugin/validate/EFM/resources/us-gaap-rels-2021.json +0 -29598
  703. arelle/plugin/validate/EFM/resources/us-gaap-rels-2022.json +0 -29141
  704. arelle/plugin/validate/EFM/resources/us-gaap-rels-2023.json +0 -29400
  705. arelle/plugin/validate/EFM/resources/vip-deprecated-concepts.json +0 -1
  706. arelle/plugin/validate/EFM/tools/CheckTxmyRefs.py +0 -180
  707. arelle/plugin/validate/EFM-htm/Const.py +0 -205
  708. arelle/plugin/validate/EFM-htm/__init__.py +0 -217
  709. arelle/plugin/validate/EFM-htm/config.xml +0 -17
  710. arelle/plugin/validate/EFM-htm/resources/efm-htm.dtd +0 -664
  711. arelle/plugin/validate/ESEF/ESEF_Current/Image.py +0 -199
  712. arelle/plugin/validate/ESEF_2022/__init__.py +0 -47
  713. arelle/plugin/validate/GFM/__init__.py +0 -59
  714. arelle/plugin/validate/GFM/config.xml +0 -82
  715. arelle/plugin/validate/SBRnl/CustomLoader.py +0 -19
  716. arelle/plugin/validate/SBRnl/DTS.py +0 -305
  717. arelle/plugin/validate/SBRnl/Dimensions.py +0 -357
  718. arelle/plugin/validate/SBRnl/Document.py +0 -799
  719. arelle/plugin/validate/SBRnl/Filing.py +0 -467
  720. arelle/plugin/validate/SBRnl/__init__.py +0 -75
  721. arelle/plugin/validate/SBRnl/config.xml +0 -26
  722. arelle/plugin/validate/SBRnl/sbr-nl-taxonomies.xml +0 -754
  723. arelle/plugin/validate/USBestPractices.py +0 -570
  724. arelle/plugin/validate/USCorpAction.py +0 -557
  725. arelle/plugin/validate/USSecTagging.py +0 -337
  726. arelle/plugin/validate/XDC/__init__.py +0 -77
  727. arelle/plugin/validate/XDC/config.xml +0 -20
  728. arelle/plugin/validate/XFsyntax/__init__.py +0 -64
  729. arelle/plugin/validate/XFsyntax/xf.py +0 -2227
  730. arelle/plugin/validate/__init__.py +0 -20
  731. arelle/plugin/validate/calc2.py +0 -536
  732. arelle/plugin/validateSBRnl.py +0 -530
  733. arelle/scripts-macOS/startWebServer.command +0 -3
  734. arelle/scripts-unix/startWebServer.sh +0 -1
  735. arelle/scripts-windows/startWebServer.bat +0 -5
  736. arelle_release-2.17.1.dist-info/RECORD +0 -676
  737. tests/__init__.py +0 -0
  738. tests/integration_tests/ui_tests/ArelleGUITest/ArelleGUITest/ArelleGUITest.csproj +0 -30
  739. tests/integration_tests/ui_tests/ArelleGUITest/ArelleGUITest/Tests.cs +0 -381
  740. tests/integration_tests/ui_tests/ArelleGUITest/ArelleGUITest/Usings.cs +0 -1
  741. tests/integration_tests/ui_tests/ArelleGUITest/ArelleGUITest.sln +0 -31
  742. tests/integration_tests/ui_tests/resources/workiva.zip +0 -0
  743. tests/integration_tests/validation/README.md +0 -50
  744. tests/integration_tests/validation/conformance_suite_config.py +0 -59
  745. tests/integration_tests/validation/conformance_suite_configs.py +0 -63
  746. tests/integration_tests/validation/conformance_suite_configurations/efm_current.py +0 -261
  747. tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2021.py +0 -85
  748. tests/integration_tests/validation/conformance_suite_configurations/esef_ixbrl_2022.py +0 -90
  749. tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2021.py +0 -15
  750. tests/integration_tests/validation/conformance_suite_configurations/esef_xhtml_2022.py +0 -15
  751. tests/integration_tests/validation/conformance_suite_configurations/nl_nt16.py +0 -13
  752. tests/integration_tests/validation/conformance_suite_configurations/nl_nt17.py +0 -13
  753. tests/integration_tests/validation/conformance_suite_configurations/nl_nt18.py +0 -13
  754. tests/integration_tests/validation/conformance_suite_configurations/xbrl_2_1.py +0 -34
  755. tests/integration_tests/validation/conformance_suite_configurations/xbrl_calculations_1_1.py +0 -40
  756. tests/integration_tests/validation/conformance_suite_configurations/xbrl_dimensions_1_0.py +0 -28
  757. tests/integration_tests/validation/conformance_suite_configurations/xbrl_extensible_enumerations_1_0.py +0 -10
  758. tests/integration_tests/validation/conformance_suite_configurations/xbrl_extensible_enumerations_2_0.py +0 -10
  759. tests/integration_tests/validation/conformance_suite_configurations/xbrl_formula_1_0.py +0 -9
  760. tests/integration_tests/validation/conformance_suite_configurations/xbrl_formula_1_0_assertion_severity_2_0.py +0 -9
  761. tests/integration_tests/validation/conformance_suite_configurations/xbrl_formula_1_0_function_registry.py +0 -14
  762. tests/integration_tests/validation/conformance_suite_configurations/xbrl_ixbrl_1_1.py +0 -22
  763. tests/integration_tests/validation/conformance_suite_configurations/xbrl_link_role_registry_1_0.py +0 -11
  764. tests/integration_tests/validation/conformance_suite_configurations/xbrl_oim_1_0.py +0 -19
  765. tests/integration_tests/validation/conformance_suite_configurations/xbrl_table_linkbase_1_0.py +0 -296
  766. tests/integration_tests/validation/conformance_suite_configurations/xbrl_taxonomy_packages_1_0.py +0 -13
  767. tests/integration_tests/validation/conformance_suite_configurations/xbrl_transformation_registry_3.py +0 -13
  768. tests/integration_tests/validation/conformance_suite_configurations/xbrl_transformation_registry_4.py +0 -13
  769. tests/integration_tests/validation/conformance_suite_configurations/xbrl_transformation_registry_5.py +0 -13
  770. tests/integration_tests/validation/conformance_suite_configurations/xbrl_utr_malformed_1_0.py +0 -31
  771. tests/integration_tests/validation/conformance_suite_configurations/xbrl_utr_registry_1_0.py +0 -22
  772. tests/integration_tests/validation/conformance_suite_configurations/xbrl_utr_structure_1_0.py +0 -18
  773. tests/integration_tests/validation/conftest.py +0 -24
  774. tests/integration_tests/validation/discover_tests.py +0 -22
  775. tests/integration_tests/validation/download_conformance_suites.py +0 -47
  776. tests/integration_tests/validation/run_conformance_suites.py +0 -175
  777. tests/integration_tests/validation/test_conformance_suites.py +0 -14
  778. tests/integration_tests/validation/validation_util.py +0 -271
  779. tests/resources/conformance_suites/nl_nt16/br_kvk/2-04-invalid-period.xbrl +0 -63
  780. tests/resources/conformance_suites/nl_nt16/br_kvk/2-04-testcase.xml +0 -22
  781. tests/resources/conformance_suites/nl_nt16/br_kvk/3-01-missing.xbrl +0 -53
  782. tests/resources/conformance_suites/nl_nt16/br_kvk/3-01-multiple.xbrl +0 -60
  783. tests/resources/conformance_suites/nl_nt16/br_kvk/3-01-testcase.xml +0 -33
  784. tests/resources/conformance_suites/nl_nt16/br_kvk/4-07-invalid.xbrl +0 -57
  785. tests/resources/conformance_suites/nl_nt16/br_kvk/4-07-testcase.xml +0 -22
  786. tests/resources/conformance_suites/nl_nt16/br_kvk/4-10-invalid.xbrl +0 -58
  787. tests/resources/conformance_suites/nl_nt16/br_kvk/4-10-testcase.xml +0 -22
  788. tests/resources/conformance_suites/nl_nt16/br_kvk/4-12-invalid.xbrl +0 -63
  789. tests/resources/conformance_suites/nl_nt16/br_kvk/4-12-testcase.xml +0 -22
  790. tests/resources/conformance_suites/nl_nt16/br_kvk/4-16-missing.xbrl +0 -61
  791. tests/resources/conformance_suites/nl_nt16/br_kvk/4-16-testcase.xml +0 -22
  792. tests/resources/conformance_suites/nl_nt16/br_kvk/4-20-invalid-date.xbrl +0 -89
  793. tests/resources/conformance_suites/nl_nt16/br_kvk/4-20-testcase.xml +0 -22
  794. tests/resources/conformance_suites/nl_nt16/fr_kvk/1-01-invalid-file-extension.xml +0 -56
  795. tests/resources/conformance_suites/nl_nt16/fr_kvk/1-01-testcase.xml +0 -22
  796. tests/resources/conformance_suites/nl_nt16/fr_kvk/2-01-invalid-lang.xbrl +0 -56
  797. tests/resources/conformance_suites/nl_nt16/fr_kvk/2-01-missing-lang.xbrl +0 -55
  798. tests/resources/conformance_suites/nl_nt16/fr_kvk/2-01-testcase.xml +0 -33
  799. tests/resources/conformance_suites/nl_nt16/fr_kvk/2-03-entrypoint.xsd +0 -6
  800. tests/resources/conformance_suites/nl_nt16/fr_kvk/2-03-invalid-entrypoint.xbrl +0 -63
  801. tests/resources/conformance_suites/nl_nt16/fr_kvk/2-03-testcase.xml +0 -22
  802. tests/resources/conformance_suites/nl_nt16/fr_kvk/5-01-invalid-decimals.xbrl +0 -49
  803. tests/resources/conformance_suites/nl_nt16/fr_kvk/5-01-testcase.xml +0 -22
  804. tests/resources/conformance_suites/nl_nt16/fr_kvk/5-02-invalid-decimals.xbrl +0 -49
  805. tests/resources/conformance_suites/nl_nt16/fr_kvk/5-02-testcase.xml +0 -22
  806. tests/resources/conformance_suites/nl_nt16/fr_nl/1-01-invalid-file.xbrl +0 -2
  807. tests/resources/conformance_suites/nl_nt16/fr_nl/1-01-invalid-zip.zip +0 -0
  808. tests/resources/conformance_suites/nl_nt16/fr_nl/1-01-testcase.xml +0 -33
  809. tests/resources/conformance_suites/nl_nt16/fr_nl/1-03-invalid-doctype.xbrl +0 -4
  810. tests/resources/conformance_suites/nl_nt16/fr_nl/1-03-testcase.xml +0 -22
  811. tests/resources/conformance_suites/nl_nt16/fr_nl/1-05-invalid-encoding.xbrl +0 -0
  812. tests/resources/conformance_suites/nl_nt16/fr_nl/1-05-testcase.xml +0 -22
  813. tests/resources/conformance_suites/nl_nt16/fr_nl/1-06-testcase.xml +0 -22
  814. tests/resources/conformance_suites/nl_nt16/fr_nl/1-06.invalid.xbrl +0 -2
  815. tests/resources/conformance_suites/nl_nt16/fr_nl/2-06-invalid-file.xbrl +0 -8
  816. tests/resources/conformance_suites/nl_nt16/fr_nl/2-06-invalid-zip.zip +0 -0
  817. tests/resources/conformance_suites/nl_nt16/fr_nl/2-06-testcase.xml +0 -33
  818. tests/resources/conformance_suites/nl_nt16/index.xml +0 -20
  819. tests/resources/conformance_suites/nl_nt17/br_kvk/2-04-invalid-period.xbrl +0 -63
  820. tests/resources/conformance_suites/nl_nt17/br_kvk/2-04-testcase.xml +0 -22
  821. tests/resources/conformance_suites/nl_nt17/br_kvk/3-01-missing.xbrl +0 -53
  822. tests/resources/conformance_suites/nl_nt17/br_kvk/3-01-multiple.xbrl +0 -60
  823. tests/resources/conformance_suites/nl_nt17/br_kvk/3-01-testcase.xml +0 -33
  824. tests/resources/conformance_suites/nl_nt17/br_kvk/4-07-invalid.xbrl +0 -57
  825. tests/resources/conformance_suites/nl_nt17/br_kvk/4-07-testcase.xml +0 -22
  826. tests/resources/conformance_suites/nl_nt17/br_kvk/4-10-invalid.xbrl +0 -58
  827. tests/resources/conformance_suites/nl_nt17/br_kvk/4-10-testcase.xml +0 -22
  828. tests/resources/conformance_suites/nl_nt17/br_kvk/4-12-invalid.xbrl +0 -63
  829. tests/resources/conformance_suites/nl_nt17/br_kvk/4-12-testcase.xml +0 -22
  830. tests/resources/conformance_suites/nl_nt17/br_kvk/4-16-missing.xbrl +0 -61
  831. tests/resources/conformance_suites/nl_nt17/br_kvk/4-16-testcase.xml +0 -22
  832. tests/resources/conformance_suites/nl_nt17/br_kvk/4-20-invalid-date.xbrl +0 -89
  833. tests/resources/conformance_suites/nl_nt17/br_kvk/4-20-testcase.xml +0 -22
  834. tests/resources/conformance_suites/nl_nt17/fr_kvk/1-01-invalid-file-extension.xml +0 -56
  835. tests/resources/conformance_suites/nl_nt17/fr_kvk/1-01-testcase.xml +0 -22
  836. tests/resources/conformance_suites/nl_nt17/fr_kvk/2-01-invalid-lang.xbrl +0 -56
  837. tests/resources/conformance_suites/nl_nt17/fr_kvk/2-01-missing-lang.xbrl +0 -55
  838. tests/resources/conformance_suites/nl_nt17/fr_kvk/2-01-testcase.xml +0 -33
  839. tests/resources/conformance_suites/nl_nt17/fr_kvk/2-03-entrypoint.xsd +0 -6
  840. tests/resources/conformance_suites/nl_nt17/fr_kvk/2-03-invalid-entrypoint.xbrl +0 -63
  841. tests/resources/conformance_suites/nl_nt17/fr_kvk/2-03-testcase.xml +0 -22
  842. tests/resources/conformance_suites/nl_nt17/fr_kvk/5-01-invalid-decimals.xbrl +0 -49
  843. tests/resources/conformance_suites/nl_nt17/fr_kvk/5-01-testcase.xml +0 -22
  844. tests/resources/conformance_suites/nl_nt17/fr_kvk/5-02-invalid-decimals.xbrl +0 -49
  845. tests/resources/conformance_suites/nl_nt17/fr_kvk/5-02-testcase.xml +0 -22
  846. tests/resources/conformance_suites/nl_nt17/fr_nl/1-01-invalid-file.xbrl +0 -2
  847. tests/resources/conformance_suites/nl_nt17/fr_nl/1-01-invalid-zip.zip +0 -0
  848. tests/resources/conformance_suites/nl_nt17/fr_nl/1-01-testcase.xml +0 -33
  849. tests/resources/conformance_suites/nl_nt17/fr_nl/1-03-invalid-doctype.xbrl +0 -4
  850. tests/resources/conformance_suites/nl_nt17/fr_nl/1-03-testcase.xml +0 -22
  851. tests/resources/conformance_suites/nl_nt17/fr_nl/1-05-invalid-encoding.xbrl +0 -0
  852. tests/resources/conformance_suites/nl_nt17/fr_nl/1-05-testcases.xml +0 -22
  853. tests/resources/conformance_suites/nl_nt17/fr_nl/1-06-testcase.xml +0 -22
  854. tests/resources/conformance_suites/nl_nt17/fr_nl/1-06.invalid.xbrl +0 -2
  855. tests/resources/conformance_suites/nl_nt17/fr_nl/2-06-invalid-file.xbrl +0 -8
  856. tests/resources/conformance_suites/nl_nt17/fr_nl/2-06-invalid-zip.zip +0 -0
  857. tests/resources/conformance_suites/nl_nt17/fr_nl/2-06-testcase.xml +0 -33
  858. tests/resources/conformance_suites/nl_nt17/index.xml +0 -20
  859. tests/resources/conformance_suites/nl_nt18/fr_nl/1-03-invalid-doctype.xbrl +0 -4
  860. tests/resources/conformance_suites/nl_nt18/fr_nl/1-03-testcase.xml +0 -22
  861. tests/resources/conformance_suites/nl_nt18/fr_nl/1-05-invalid-encoding.xbrl +0 -0
  862. tests/resources/conformance_suites/nl_nt18/fr_nl/1-05-testcases.xml +0 -22
  863. tests/resources/conformance_suites/nl_nt18/fr_nl/1-06-testcase.xml +0 -22
  864. tests/resources/conformance_suites/nl_nt18/fr_nl/1-06.invalid.xbrl +0 -2
  865. tests/resources/conformance_suites/nl_nt18/fr_nl/1.01-invalid-file.xbrl +0 -2
  866. tests/resources/conformance_suites/nl_nt18/fr_nl/1.01-invalid-zip.zip +0 -0
  867. tests/resources/conformance_suites/nl_nt18/fr_nl/1.01-testcase.xml +0 -33
  868. tests/resources/conformance_suites/nl_nt18/fr_nl/2-06-invalid-file.xbrl +0 -8
  869. tests/resources/conformance_suites/nl_nt18/fr_nl/2-06-invalid-zip.zip +0 -0
  870. tests/resources/conformance_suites/nl_nt18/fr_nl/2-06-testcase.xml +0 -33
  871. tests/resources/conformance_suites/nl_nt18/index.xml +0 -8
  872. tests/unit_tests/arelle/conftest.py +0 -16
  873. tests/unit_tests/arelle/formula/test_fact_aspects_cache.py +0 -170
  874. tests/unit_tests/arelle/plugin/test_loadfromoim.py +0 -40
  875. tests/unit_tests/arelle/plugin/test_plugin_imports.py +0 -27
  876. tests/unit_tests/arelle/test_betafeatures.py +0 -81
  877. tests/unit_tests/arelle/test_cntlr.py +0 -28
  878. tests/unit_tests/arelle/test_import.py +0 -40
  879. tests/unit_tests/arelle/test_locale.py +0 -73
  880. tests/unit_tests/arelle/test_modelmanager.py +0 -15
  881. tests/unit_tests/arelle/test_packagemanager.py +0 -65
  882. tests/unit_tests/arelle/test_pluginmanager.py +0 -176
  883. tests/unit_tests/arelle/test_qname.py +0 -140
  884. tests/unit_tests/arelle/test_runtimeoptions.py +0 -56
  885. tests/unit_tests/arelle/test_system_info.py +0 -26
  886. tests/unit_tests/arelle/test_updater.py +0 -507
  887. tests/unit_tests/arelle/test_urlutil.py +0 -49
  888. tests/unit_tests/arelle/test_version.py +0 -46
  889. tests/unit_tests/arelle/utils/validate/test_decorator.py +0 -59
  890. /arelle/{examples/plugin/validate/XYZ → plugin/validate/EDINET}/rules/__init__.py +0 -0
  891. /arelle/plugin/validate/{HMRC → UK}/consistencyChecksByName.json +0 -0
  892. /arelle/plugin/validate/{HMRC → UK}/hmrc-taxonomies.xml +0 -0
  893. {arelle_release-2.17.1.dist-info → arelle_release-2.37.71.dist-info}/entry_points.txt +0 -0
arelle/PluginManager.py CHANGED
@@ -1,29 +1,41 @@
1
1
  '''
2
2
  See COPYRIGHT.md for copyright information.
3
-
4
- based on pull request 4
5
-
6
3
  '''
7
4
  from __future__ import annotations
8
- import os, sys, types, time, ast, importlib, io, json, gettext, traceback
9
- from importlib.metadata import entry_points, EntryPoint
5
+
6
+ import ast
7
+ import gettext
8
+ from glob import glob
10
9
  import importlib.util
10
+ import json
11
11
  import logging
12
-
12
+ import os
13
+ import sys
14
+ import time
15
+ import traceback
16
+ import types
17
+ from collections import defaultdict
18
+ from collections.abc import Callable, Iterator
19
+ from dataclasses import dataclass
20
+ from importlib.metadata import EntryPoint, entry_points
21
+ from numbers import Number
22
+ from pathlib import Path
13
23
  from types import ModuleType
14
- from typing import TYPE_CHECKING, Any, Iterator, Callable
15
- from arelle.Locale import getLanguageCodes
24
+ from typing import TYPE_CHECKING, Any, cast
25
+
16
26
  import arelle.FileSource
27
+ from arelle.Locale import getLanguageCodes
28
+ from arelle.PythonUtil import isLegacyAbs
29
+ from arelle.typing import TypeGetText
17
30
  from arelle.UrlUtil import isAbsolute
18
- from pathlib import Path
19
- from collections import OrderedDict, defaultdict
20
- from collections.abc import Callable
21
-
22
31
 
23
32
  if TYPE_CHECKING:
24
33
  # Prevent potential circular import error
25
34
  from .Cntlr import Cntlr
26
35
 
36
+
37
+ _: TypeGetText
38
+
27
39
  PLUGIN_TRACE_FILE = None
28
40
  # PLUGIN_TRACE_FILE = "c:/temp/pluginerr.txt"
29
41
  PLUGIN_TRACE_LEVEL = logging.WARNING
@@ -56,7 +68,7 @@ def init(cntlr: Cntlr, loadPluginConfig: bool = True) -> None:
56
68
  if loadPluginConfig:
57
69
  try:
58
70
  pluginJsonFile = cntlr.userAppDir + os.sep + "plugins.json"
59
- with io.open(pluginJsonFile, 'rt', encoding='utf-8') as f:
71
+ with open(pluginJsonFile, encoding='utf-8') as f:
60
72
  pluginConfig = json.load(f)
61
73
  freshenModuleInfos()
62
74
  except Exception:
@@ -70,42 +82,63 @@ def init(cntlr: Cntlr, loadPluginConfig: bool = True) -> None:
70
82
  modulePluginInfos = {} # dict of loaded module pluginInfo objects by module names
71
83
  pluginMethodsForClasses = {} # dict by class of list of ordered callable function objects
72
84
 
73
- def reset(): # force reloading modules and plugin infos
74
- modulePluginInfos.clear() # dict of loaded module pluginInfo objects by module names
75
- pluginMethodsForClasses.clear() # dict by class of list of ordered callable function objects
85
+ def reset() -> None: # force reloading modules and plugin infos
86
+ if modulePluginInfos:
87
+ modulePluginInfos.clear() # dict of loaded module pluginInfo objects by module names
88
+ if pluginMethodsForClasses:
89
+ pluginMethodsForClasses.clear() # dict by class of list of ordered callable function objects
76
90
 
77
91
  def orderedPluginConfig():
78
- return OrderedDict(
79
- (('modules',OrderedDict((moduleName,
80
- OrderedDict(sorted(moduleInfo.items(),
81
- key=lambda k: {'name': '01',
82
- 'status': '02',
83
- 'version': '03',
84
- 'fileDate': '04', 'version': '05',
85
- 'description': '05',
86
- 'moduleURL': '06',
87
- 'localeURL': '07',
88
- 'localeDomain': '08',
89
- 'license': '09',
90
- 'author': '10',
91
- 'copyright': '11',
92
- 'classMethods': '12'}.get(k[0],k[0]))))
93
- for moduleName, moduleInfo in sorted(pluginConfig['modules'].items()))),
94
- ('classes',OrderedDict(sorted(pluginConfig['classes'].items())))))
92
+ fieldOrder = [
93
+ 'name',
94
+ 'status',
95
+ 'fileDate',
96
+ 'version',
97
+ 'description',
98
+ 'moduleURL',
99
+ 'localeURL',
100
+ 'localeDomain',
101
+ 'license',
102
+ 'author',
103
+ 'copyright',
104
+ 'classMethods',
105
+ ]
106
+ priorityIndex = {k: i for i, k in enumerate(fieldOrder)}
107
+
108
+ def sortModuleInfo(moduleInfo):
109
+ # Prioritize known fields by the index in fieldOrder; sort others alphabetically
110
+ orderedKeys = sorted(
111
+ moduleInfo.keys(),
112
+ key=lambda k: (priorityIndex.get(k, len(priorityIndex)), k)
113
+ )
114
+ return {k: moduleInfo[k] for k in orderedKeys}
115
+
116
+ orderedModules = {
117
+ moduleName: sortModuleInfo(pluginConfig['modules'][moduleName])
118
+ for moduleName in sorted(pluginConfig['modules'].keys())
119
+ }
120
+
121
+ return {
122
+ 'modules': orderedModules,
123
+ 'classes': dict(sorted(pluginConfig['classes'].items()))
124
+ }
95
125
 
96
126
  def save(cntlr: Cntlr) -> None:
97
127
  global pluginConfigChanged
98
128
  if pluginConfigChanged and cntlr.hasFileSystem and not cntlr.disablePersistentConfig:
99
129
  pluginJsonFile = cntlr.userAppDir + os.sep + "plugins.json"
100
- with io.open(pluginJsonFile, 'wt', encoding='utf-8') as f:
130
+ with open(pluginJsonFile, 'w', encoding='utf-8') as f:
101
131
  jsonStr = str(json.dumps(orderedPluginConfig(), ensure_ascii=False, indent=2)) # might not be unicode in 2.7
102
132
  f.write(jsonStr)
103
133
  pluginConfigChanged = False
104
134
 
105
- def close(): # close all loaded methods
106
- pluginConfig.clear()
107
- modulePluginInfos.clear()
108
- pluginMethodsForClasses.clear()
135
+ def close() -> None: # close all loaded methods
136
+ if pluginConfig is not None:
137
+ pluginConfig.clear()
138
+ if modulePluginInfos is not None:
139
+ modulePluginInfos.clear()
140
+ if pluginMethodsForClasses is not None:
141
+ pluginMethodsForClasses.clear()
109
142
  global webCache
110
143
  webCache = None
111
144
 
@@ -148,7 +181,6 @@ moduleInfo = {
148
181
 
149
182
  '''
150
183
 
151
-
152
184
  def logPluginTrace(message: str, level: Number) -> None:
153
185
  """
154
186
  If plugin trace file logging is configured, logs `message` to it.
@@ -156,7 +188,6 @@ def logPluginTrace(message: str, level: Number) -> None:
156
188
  :param message: Message to be logged
157
189
  :param level: Log level of message (e.g. logging.INFO)
158
190
  """
159
- global pluginTraceFileLogger
160
191
  if pluginTraceFileLogger:
161
192
  pluginTraceFileLogger.log(level, message)
162
193
  if level >= logging.ERROR:
@@ -188,8 +219,9 @@ def modulesWithNewerFileDates():
188
219
 
189
220
  def freshenModuleInfos():
190
221
  # for modules with different date-times, re-load module info
191
- for moduleName in pluginConfig["modules"].keys():
192
- moduleInfo = pluginConfig["modules"][moduleName]
222
+ missingEnabledModules = []
223
+ for moduleName, moduleInfo in pluginConfig["modules"].items():
224
+ moduleEnabled = moduleInfo["status"] == "enabled"
193
225
  freshenedFilename = _cntlr.webCache.getfilename(moduleInfo["moduleURL"], checkModifiedTime=True, normalize=True, base=_pluginBase)
194
226
  try: # check if moduleInfo cached may differ from referenced moduleInfo
195
227
  if os.path.isdir(freshenedFilename): # if freshenedFilename is a directory containing an __ini__.py file, open that instead
@@ -199,9 +231,17 @@ def freshenModuleInfos():
199
231
  freshenedFilename += ".py" # extension module without .py suffix
200
232
  if os.path.exists(freshenedFilename):
201
233
  if moduleInfo["fileDate"] != time.strftime('%Y-%m-%dT%H:%M:%S UTC', time.gmtime(os.path.getmtime(freshenedFilename))):
202
- freshenedModuleInfo = moduleModuleInfo(moduleInfo["moduleURL"], reload=True)
234
+ freshenedModuleInfo = moduleModuleInfo(moduleURL=moduleInfo["moduleURL"], reload=True)
203
235
  if freshenedModuleInfo is not None:
204
- pluginConfig["modules"][moduleName] = freshenedModuleInfo
236
+ if freshenedModuleInfo["name"] == moduleName:
237
+ pluginConfig["modules"][moduleName] = freshenedModuleInfo
238
+ else:
239
+ # Module has been re-named
240
+ if moduleEnabled:
241
+ missingEnabledModules.append(moduleName)
242
+ # User can avoid pruning by disabling plugin
243
+ elif moduleEnabled:
244
+ missingEnabledModules.append(moduleName)
205
245
  else:
206
246
  _msg = _("File not found for '{name}' plug-in when attempting to update module info. Path: '{path}'")\
207
247
  .format(name=moduleName, path=freshenedFilename)
@@ -209,135 +249,267 @@ def freshenModuleInfos():
209
249
  except Exception as err:
210
250
  _msg = _("Exception at plug-in method freshenModuleInfos: {error}").format(error=err)
211
251
  logPluginTrace(_msg, logging.ERROR)
252
+ for moduleName in missingEnabledModules:
253
+ removePluginModule(moduleName)
254
+ # Try re-adding plugin modules by name (for plugins that moved from built-in to pip installed)
255
+ moduleInfo = addPluginModule(moduleName)
256
+ if moduleInfo:
257
+ pluginConfig["modules"][moduleInfo["name"]] = moduleInfo
258
+ loadModule(moduleInfo)
259
+ logPluginTrace(_("Reloaded plugin that failed loading: {} {}").format(moduleName, moduleInfo), logging.INFO)
260
+ else:
261
+ logPluginTrace(_("Removed plugin that failed loading (plugin may have been archived): {}").format(moduleName), logging.ERROR)
262
+ save(_cntlr)
263
+
212
264
 
213
- def moduleModuleInfo(moduleURL, reload=False, parentImportsSubtree=False):
265
+ def normalizeModuleFilename(moduleFilename: str) -> str | None:
266
+ """
267
+ Attempts to find python script as plugin entry point.
268
+ A value will be returned
269
+ if `moduleFilename` exists as-is,
270
+ if `moduleFilename` is a directory containing __init__.py, or
271
+ if `moduleFilename` with .py extension added exists
272
+ :param moduleFilename:
273
+ :return: Normalized filename, if exists
274
+ """
275
+ if os.path.isfile(moduleFilename):
276
+ # moduleFilename exists as-is, use it
277
+ return moduleFilename
278
+ if os.path.isdir(moduleFilename):
279
+ # moduleFilename is a directory, only valid script is __init__.py contained inside
280
+ initPath = os.path.join(moduleFilename, "__init__.py")
281
+ if os.path.isfile(initPath):
282
+ return initPath
283
+ else:
284
+ return None
285
+ if not moduleFilename.endswith(".py"):
286
+ # moduleFilename is not a file or directory, try adding .py
287
+ pyPath = moduleFilename + ".py"
288
+ if os.path.exists(pyPath):
289
+ return pyPath
290
+ return None
291
+
292
+
293
+ def getModuleFilename(moduleURL: str, reload: bool, normalize: bool, base: str | None) -> tuple[str | None, EntryPoint | None]:
214
294
  #TODO several directories, eg User Application Data
215
- moduleFilename = _cntlr.webCache.getfilename(moduleURL, reload=reload, normalize=True, base=_pluginBase)
295
+ moduleFilename = _cntlr.webCache.getfilename(moduleURL, reload=reload, normalize=normalize, base=base)
296
+ if moduleFilename:
297
+ # `moduleURL` was mapped to a local filepath
298
+ moduleFilename = normalizeModuleFilename(moduleFilename)
299
+ if moduleFilename:
300
+ # `moduleFilename` normalized to an existing script
301
+ return moduleFilename, None
302
+ if base and not _isAbsoluteModuleURL(moduleURL):
303
+ # Search for a matching plugin deeper in the plugin directory tree.
304
+ # Handles cases where a plugin exists in a nested structure, such as
305
+ # when a developer clones an entire repository into the plugin directory.
306
+ # Example: arelle/plugin/xule/plugin/xule/__init__.py
307
+ for path in glob("**/" + moduleURL.replace('\\', '/'), recursive=True):
308
+ if normalizedPath := normalizeModuleFilename(path):
309
+ return normalizedPath, None
310
+ # `moduleFilename` did not map to a local filepath or did not normalize to a script
311
+ # Try using `moduleURL` to search for pip-installed entry point
312
+ entryPointRef = EntryPointRef.get(moduleURL)
313
+ if entryPointRef is not None:
314
+ return entryPointRef.moduleFilename, entryPointRef.entryPoint
315
+ return None, None
316
+
317
+
318
+ def parsePluginInfo(moduleURL: str, moduleFilename: str, entryPoint: EntryPoint | None) -> dict | None:
319
+ moduleDir, moduleName = os.path.split(moduleFilename)
320
+ f = arelle.FileSource.openFileStream(_cntlr, moduleFilename)
321
+ tree = ast.parse(f.read(), filename=moduleFilename)
322
+ constantStrings = {}
323
+ functionDefNames = set()
324
+ methodDefNamesByClass = defaultdict(set)
325
+ moduleImports = []
326
+ moduleInfo = {"name":None}
327
+ isPlugin = False
328
+ for item in tree.body:
329
+ if isinstance(item, ast.Assign):
330
+ try:
331
+ attr = item.targets[0].id
332
+ except AttributeError:
333
+ # Not plugininfo
334
+ continue
335
+ if attr == "__pluginInfo__":
336
+ isPlugin = True
337
+ f.close()
338
+ classMethods = []
339
+ importURLs = []
340
+ for i, key in enumerate(item.value.keys):
341
+ _key = key.value
342
+ _value = item.value.values[i]
343
+ _valueType = _value.__class__.__name__
344
+ if _key == "import":
345
+ if _valueType == 'Constant':
346
+ importURLs.append(_value.value)
347
+ elif _valueType in ("List", "Tuple"):
348
+ for elt in _value.elts:
349
+ importURLs.append(elt.value)
350
+ elif _valueType == 'Constant':
351
+ moduleInfo[_key] = _value.value
352
+ elif _valueType == 'Name':
353
+ if _value.id in constantStrings:
354
+ moduleInfo[_key] = constantStrings[_value.id]
355
+ elif _value.id in functionDefNames:
356
+ classMethods.append(_key)
357
+ elif _valueType == 'Attribute':
358
+ if _value.attr in methodDefNamesByClass[_value.value.id]:
359
+ classMethods.append(_key)
360
+ elif _valueType in ("List", "Tuple"):
361
+ values = [elt.value for elt in _value.elts]
362
+ if _key == "imports":
363
+ importURLs = values
364
+ else:
365
+ moduleInfo[_key] = values
366
+
367
+ moduleInfo['classMethods'] = classMethods
368
+ moduleInfo['importURLs'] = importURLs
369
+ moduleInfo["moduleURL"] = moduleURL
370
+ moduleInfo["path"] = moduleFilename
371
+ moduleInfo["status"] = 'enabled'
372
+ moduleInfo["fileDate"] = time.strftime('%Y-%m-%dT%H:%M:%S UTC', time.gmtime(os.path.getmtime(moduleFilename)))
373
+ if entryPoint:
374
+ moduleInfo["moduleURL"] = moduleFilename # pip-installed plugins need absolute filepath
375
+ moduleInfo["entryPoint"] = {
376
+ "module": entryPoint.module,
377
+ "name": entryPoint.name,
378
+ "version": entryPoint.dist.version if hasattr(entryPoint, 'dist') else None,
379
+ }
380
+ if not moduleInfo.get("version"):
381
+ moduleInfo["version"] = entryPoint.dist.version # If no explicit version, retrieve from entry point
382
+ elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str): # possible constant used in plugininfo, such as VERSION
383
+ for assignmentName in item.targets:
384
+ constantStrings[assignmentName.id] = item.value.value
385
+ elif isinstance(item, ast.ImportFrom):
386
+ if item.level == 1: # starts with .
387
+ if item.module is None: # from . import module1, module2, ...
388
+ for importee in item.names:
389
+ if importee.name == '*': #import all submodules
390
+ for _file in os.listdir(moduleDir):
391
+ if _file != moduleName and os.path.isfile(_file) and _file.endswith(".py"):
392
+ moduleImports.append(_file)
393
+ elif (os.path.isfile(os.path.join(moduleDir, importee.name + ".py"))
394
+ and importee.name not in moduleImports):
395
+ moduleImports.append(importee.name)
396
+ else:
397
+ modulePkgs = item.module.split('.')
398
+ modulePath = os.path.join(*modulePkgs)
399
+ if (os.path.isfile(os.path.join(moduleDir, modulePath) + ".py")
400
+ and modulePath not in moduleImports):
401
+ moduleImports.append(modulePath)
402
+ for importee in item.names:
403
+ _importeePfxName = os.path.join(modulePath, importee.name)
404
+ if (os.path.isfile(os.path.join(moduleDir, _importeePfxName) + ".py")
405
+ and _importeePfxName not in moduleImports):
406
+ moduleImports.append(_importeePfxName)
407
+ elif isinstance(item, ast.FunctionDef): # possible functionDef used in plugininfo
408
+ functionDefNames.add(item.name)
409
+ elif isinstance(item, ast.ClassDef): # possible ClassDef used in plugininfo
410
+ for classItem in item.body:
411
+ if isinstance(classItem, ast.FunctionDef):
412
+ methodDefNamesByClass[item.name].add(classItem.name)
413
+ moduleInfo["moduleImports"] = moduleImports
414
+ f.close()
415
+ return moduleInfo if isPlugin else None
416
+
417
+
418
+ def moduleModuleInfo(
419
+ moduleURL: str | None = None,
420
+ entryPoint: EntryPoint | None = None,
421
+ reload: bool = False,
422
+ parentImportsSubtree: bool = False) -> dict | None:
423
+ """
424
+ Generates a module info dict based on the provided `moduleURL` or `entryPoint`
425
+ Exactly one of "moduleURL" or "entryPoint" must be provided, otherwise a RuntimeError will be thrown.
426
+
427
+ When `moduleURL` is provided, it will be treated as a file path and will attempt to be normalized and
428
+ mapped to an existing plugin based on file location. If `moduleURL` fails to be mapped to an existing
429
+ plugin on its own, it will instead be used to search for an entry point. If found, this function will
430
+ proceed as if that entry point was provided for `entryPoint`.
431
+
432
+ When `entryPoint` is provided, it's location and other details will be used to generate the module info
433
+ dictionary.
434
+
435
+ :param moduleURL: A URL that loosely maps to the file location of a plugin (may be transformed)
436
+ :param entryPoint: An `EntryPoint` instance
437
+ :param reload:
438
+ :param parentImportsSubtree:
439
+ :return:s
440
+ """
441
+ if (moduleURL is None) == (entryPoint is None):
442
+ raise RuntimeError('Exactly one of "moduleURL" or "entryPoint" must be provided')
443
+ if entryPoint:
444
+ # If entry point is provided, use it to retrieve `moduleFilename`
445
+ moduleFilename = moduleURL = entryPoint.load()()
446
+ else:
447
+ # Otherwise, we will verify the path before continuing
448
+ moduleFilename, entryPoint = getModuleFilename(moduleURL, reload=reload, normalize=True, base=_pluginBase)
449
+
216
450
  if moduleFilename:
217
- f = None
218
451
  try:
219
- # if moduleFilename is a directory containing an __ini__.py file, open that instead
220
- if os.path.isdir(moduleFilename):
221
- if os.path.isfile(os.path.join(moduleFilename, "__init__.py")):
222
- moduleFilename = os.path.join(moduleFilename, "__init__.py")
223
- else: # impossible to get a moduleinfo from a directory without an __init__.py
224
- return None
225
- elif not moduleFilename.endswith(".py") and not os.path.exists(moduleFilename) and os.path.exists(moduleFilename + ".py"):
226
- moduleFilename += ".py" # extension module without .py suffix
452
+ logPluginTrace(f"Scanning module for plug-in info: {moduleFilename}", logging.INFO)
453
+ moduleInfo = parsePluginInfo(moduleURL, moduleFilename, entryPoint)
454
+ if moduleInfo is None:
455
+ return None
456
+
227
457
  moduleDir, moduleName = os.path.split(moduleFilename)
228
- logPluginTrace("Scanning module for plug-in info: {}".format(moduleFilename), logging.INFO)
229
- f = arelle.FileSource.openFileStream(_cntlr, moduleFilename)
230
- tree = ast.parse(f.read(), filename=moduleFilename)
231
- constantStrings = {}
232
- functionDefNames = set()
233
- methodDefNamesByClass = defaultdict(set)
234
- moduleImports = []
235
- for item in tree.body:
236
- if isinstance(item, ast.Assign):
237
- attr = item.targets[0].id
238
- if attr == "__pluginInfo__":
239
- f.close()
240
- moduleInfo = {"name":None}
241
- classMethods = []
242
- importURLs = []
243
- for i, key in enumerate(item.value.keys):
244
- _key = key.s
245
- _value = item.value.values[i]
246
- _valueType = _value.__class__.__name__
247
- if _key == "import":
248
- if _valueType == 'Constant':
249
- importURLs.append(_value.s)
250
- elif _valueType in ("List", "Tuple"):
251
- for elt in _value.elts:
252
- importURLs.append(elt.s)
253
- elif _valueType == 'Constant':
254
- moduleInfo[_key] = _value.s
255
- elif _valueType == 'Name':
256
- if _value.id in constantStrings:
257
- moduleInfo[_key] = constantStrings[_value.id]
258
- elif _value.id in functionDefNames:
259
- classMethods.append(_key)
260
- elif _valueType == 'Attribute':
261
- if _value.attr in methodDefNamesByClass[_value.value.id]:
262
- classMethods.append(_key)
263
- elif _key == "imports" and _valueType in ("List", "Tuple"):
264
- importURLs = [elt.s for elt in _value.elts]
265
- moduleInfo['classMethods'] = classMethods
266
- moduleInfo["moduleURL"] = moduleURL
267
- moduleInfo["status"] = 'enabled'
268
- moduleInfo["fileDate"] = time.strftime('%Y-%m-%dT%H:%M:%S UTC', time.gmtime(os.path.getmtime(moduleFilename)))
269
- mergedImportURLs = []
270
- _moduleImportsSubtree = False
271
- for _url in importURLs:
272
- if _url.startswith("module_import"):
273
- for moduleImport in moduleImports:
274
- mergedImportURLs.append(moduleImport + ".py")
275
- if _url == "module_import_subtree":
276
- _moduleImportsSubtree = True
277
- elif _url == "module_subtree":
278
- for _dir in os.listdir(moduleDir):
279
- _subtreeModule = os.path.join(moduleDir,_dir)
280
- if os.path.isdir(_subtreeModule) and _dir != "__pycache__":
281
- mergedImportURLs.append(_subtreeModule)
282
- else:
283
- mergedImportURLs.append(_url)
284
- if parentImportsSubtree and not _moduleImportsSubtree:
285
- _moduleImportsSubtree = True
286
- for moduleImport in moduleImports:
287
- mergedImportURLs.append(moduleImport + ".py")
288
- imports = []
289
- for _url in mergedImportURLs:
290
- if isAbsolute(_url) or os.path.isabs(_url):
291
- _importURL = _url # URL is absolute http or local file system
292
- else: # check if exists relative to this module's directory
293
- _importURL = os.path.join(os.path.dirname(moduleURL), os.path.normpath(_url))
294
- if not os.path.exists(_importURL): # not relative to this plugin, assume standard plugin base
295
- _importURL = _url # moduleModuleInfo adjusts relative URL to plugin base
296
- _importModuleInfo = moduleModuleInfo(_importURL, reload, _moduleImportsSubtree)
297
- if _importModuleInfo:
298
- _importModuleInfo["isImported"] = True
299
- imports.append(_importModuleInfo)
300
- moduleInfo["imports"] = imports
301
- return moduleInfo
302
- elif isinstance(item.value, ast.Str): # possible constant used in plugininfo, such as VERSION
303
- for assignmentName in item.targets:
304
- constantStrings[assignmentName.id] = item.value.s
305
- elif isinstance(item, ast.ImportFrom):
306
- if item.level == 1: # starts with .
307
- if item.module is None: # from . import module1, module2, ...
308
- for importee in item.names:
309
- if importee.name == '*': #import all submodules
310
- for _file in os.listdir(moduleDir):
311
- if _file != moduleFile and os.path.isfile(_file) and _file.endswith(".py"):
312
- moduleImports.append(_file)
313
- elif (os.path.isfile(os.path.join(moduleDir, importee.name + ".py"))
314
- and importee.name not in moduleImports):
315
- moduleImports.append(importee.name)
316
- else:
317
- modulePkgs = item.module.split('.')
318
- modulePath = os.path.join(*modulePkgs)
319
- if (os.path.isfile(os.path.join(moduleDir, modulePath) + ".py")
320
- and modulePath not in moduleImports):
321
- moduleImports.append(modulePath)
322
- for importee in item.names:
323
- _importeePfxName = os.path.join(modulePath, importee.name)
324
- if (os.path.isfile(os.path.join(moduleDir, _importeePfxName) + ".py")
325
- and _importeePfxName not in moduleImports):
326
- moduleImports.append(_importeePfxName)
327
- elif isinstance(item, ast.FunctionDef): # possible functionDef used in plugininfo
328
- functionDefNames.add(item.name)
329
- elif isinstance(item, ast.ClassDef): # possible ClassDef used in plugininfo
330
- for classItem in item.body:
331
- if isinstance(classItem, ast.FunctionDef):
332
- methodDefNamesByClass[item.name].add(classItem.name)
458
+ importURLs = moduleInfo["importURLs"]
459
+ del moduleInfo["importURLs"]
460
+ moduleImports = moduleInfo["moduleImports"]
461
+ del moduleInfo["moduleImports"]
462
+ moduleImportsSubtree = False
463
+ mergedImportURLs = []
464
+
465
+ for url in importURLs:
466
+ if url.startswith("module_import"):
467
+ for moduleImport in moduleImports:
468
+ mergedImportURLs.append(moduleImport + ".py")
469
+ if url == "module_import_subtree":
470
+ moduleImportsSubtree = True
471
+ elif url == "module_subtree":
472
+ for _dir in os.listdir(moduleDir):
473
+ subtreeModule = os.path.join(moduleDir,_dir)
474
+ if os.path.isdir(subtreeModule) and _dir != "__pycache__":
475
+ mergedImportURLs.append(subtreeModule)
476
+ else:
477
+ mergedImportURLs.append(url)
478
+ if parentImportsSubtree and not moduleImportsSubtree:
479
+ moduleImportsSubtree = True
480
+ for moduleImport in moduleImports:
481
+ mergedImportURLs.append(moduleImport + ".py")
482
+ imports = []
483
+ for url in mergedImportURLs:
484
+ importURL = url
485
+ if not _isAbsoluteModuleURL(url):
486
+ # Handle relative imports when plugin is loaded from external directory.
487
+ # When EDGAR/render imports EDGAR/validate, this works if EDGAR is in the plugin directory
488
+ # but fails if loaded externally (e.g., dev repo clone at /dev/path/to/EDGAR/).
489
+ # Solution: Find common path segments to resolve /dev/path/to/EDGAR/validate
490
+ # from the importing module at /dev/path/to/EDGAR/render.
491
+ modulePath = Path(moduleFilename)
492
+ importPath = Path(url)
493
+ if importPath.parts:
494
+ importFirstPart = importPath.parts[0]
495
+ for i, modulePathPart in enumerate(reversed(modulePath.parts)):
496
+ if modulePathPart != importFirstPart:
497
+ continue
498
+ # Found a potential branching point, construct and check a new path
499
+ candidateImportURL = str(modulePath.parents[i] / importPath)
500
+ if normalizeModuleFilename(candidateImportURL):
501
+ importURL = candidateImportURL
502
+ importModuleInfo = moduleModuleInfo(moduleURL=importURL, reload=reload, parentImportsSubtree=moduleImportsSubtree)
503
+ if importModuleInfo:
504
+ importModuleInfo["isImported"] = True
505
+ imports.append(importModuleInfo)
506
+ moduleInfo["imports"] = imports
333
507
  logPluginTrace(f"Successful module plug-in info: {moduleFilename}", logging.INFO)
508
+ return moduleInfo
334
509
  except Exception as err:
335
510
  _msg = _("Exception obtaining plug-in module info: {moduleFilename}\n{error}\n{traceback}").format(
336
511
  error=err, moduleFilename=moduleFilename, traceback=traceback.format_tb(sys.exc_info()[2]))
337
512
  logPluginTrace(_msg, logging.ERROR)
338
-
339
- if f:
340
- f.close()
341
513
  return None
342
514
 
343
515
 
@@ -350,43 +522,30 @@ def moduleInfo(pluginInfo):
350
522
  moduleInfo.getdefault('classes', []).append(name)
351
523
 
352
524
 
353
- def _get_name_dir_prefix(
354
- controller: Cntlr,
355
- pluginBase: str,
356
- moduleURL: str,
357
- packagePrefix: str = "",
358
- ) -> tuple[str, str, str] | tuple[None, None, None]:
359
- """Get the name, directory and prefix of a module."""
360
- moduleFilename: str
361
- moduleDir: str
362
- packageImportPrefix: str
525
+ def _isAbsoluteModuleURL(moduleURL: str) -> bool:
526
+ return isAbsolute(moduleURL) or isLegacyAbs(moduleURL)
363
527
 
364
- moduleFilename = controller.webCache.getfilename(
365
- url=moduleURL, normalize=True, base=pluginBase
366
- )
367
528
 
368
- if moduleFilename:
369
- if os.path.basename(moduleFilename) == "__init__.py" and os.path.isfile(
370
- moduleFilename
371
- ):
372
- moduleFilename = os.path.dirname(
373
- moduleFilename
374
- ) # want just the dirpart of package
375
-
376
- if os.path.isdir(moduleFilename) and os.path.isfile(
377
- os.path.join(moduleFilename, "__init__.py")
378
- ):
379
- moduleDir = os.path.dirname(moduleFilename)
380
- moduleName = os.path.basename(moduleFilename)
381
- packageImportPrefix = moduleName + "."
382
- else:
383
- moduleName = os.path.basename(moduleFilename).partition(".")[0]
384
- moduleDir = os.path.dirname(moduleFilename)
385
- packageImportPrefix = packagePrefix
529
+ def _get_name_dir_prefix(modulePath: Path, packagePrefix: str = "") -> tuple[str, str, str] | tuple[None, None, None]:
530
+ """Get the name, directory and prefix of a module."""
531
+ moduleName = None
532
+ moduleDir = None
533
+ packageImportPrefix = None
534
+ initFileName = "__init__.py"
535
+
536
+ if modulePath.is_file() and modulePath.name == initFileName:
537
+ modulePath = modulePath.parent
386
538
 
387
- return (moduleName, moduleDir, packageImportPrefix)
539
+ if modulePath.is_dir() and (modulePath / initFileName).is_file():
540
+ moduleName = modulePath.name
541
+ moduleDir = str(modulePath.parent)
542
+ packageImportPrefix = moduleName + "."
543
+ elif modulePath.is_file() and modulePath.suffix == ".py":
544
+ moduleName = modulePath.stem
545
+ moduleDir = str(modulePath.parent)
546
+ packageImportPrefix = packagePrefix
388
547
 
389
- return (None, None, None)
548
+ return (moduleName, moduleDir, packageImportPrefix)
390
549
 
391
550
  def _get_location(moduleDir: str, moduleName: str) -> str:
392
551
  """Get the file name of a plugin."""
@@ -416,13 +575,9 @@ def _find_and_load_module(moduleDir: str, moduleName: str) -> ModuleType | None:
416
575
  def loadModule(moduleInfo: dict[str, Any], packagePrefix: str="") -> None:
417
576
  name = moduleInfo['name']
418
577
  moduleURL = moduleInfo['moduleURL']
578
+ modulePath = Path(moduleInfo['path'])
419
579
 
420
- moduleName, moduleDir, packageImportPrefix = _get_name_dir_prefix(
421
- controller=_cntlr,
422
- pluginBase=_pluginBase,
423
- moduleURL=moduleURL,
424
- packagePrefix=packagePrefix,
425
- )
580
+ moduleName, moduleDir, packageImportPrefix = _get_name_dir_prefix(modulePath, packagePrefix)
426
581
 
427
582
  if all(p is None for p in [moduleName, moduleDir, packageImportPrefix]):
428
583
  _cntlr.addToLog(message=_ERROR_MESSAGE_IMPORT_TEMPLATE.format(name), level=logging.ERROR)
@@ -439,10 +594,12 @@ def loadModule(moduleInfo: dict[str, Any], packagePrefix: str="") -> None:
439
594
  localeDir = os.path.dirname(module.__file__) + os.sep + pluginInfo['localeURL']
440
595
  try:
441
596
  _gettext = gettext.translation(pluginInfo['localeDomain'], localeDir, getLanguageCodes())
442
- except IOError:
443
- _gettext = lambda x: x # no translation
597
+ except OSError:
598
+ def _gettext(x):
599
+ return x # no translation
444
600
  else:
445
- _gettext = lambda x: x
601
+ def _gettext(x):
602
+ return x
446
603
  for key, value in pluginInfo.items():
447
604
  if key == 'name':
448
605
  if name:
@@ -474,6 +631,11 @@ def loadModule(moduleInfo: dict[str, Any], packagePrefix: str="") -> None:
474
631
  name=name, error=err, traceback=traceback.format_tb(sys.exc_info()[2]))
475
632
  logPluginTrace(_msg, logging.ERROR)
476
633
 
634
+
635
+ def hasPluginWithHook(name: str) -> bool:
636
+ return next(pluginClassMethods(name), None) is not None
637
+
638
+
477
639
  def pluginClassMethods(className: str) -> Iterator[Callable[..., Any]]:
478
640
  if pluginConfig:
479
641
  try:
@@ -495,8 +657,7 @@ def pluginClassMethods(className: str) -> Iterator[Callable[..., Any]]:
495
657
  if className in pluginInfo:
496
658
  pluginMethodsForClass.append(pluginInfo[className])
497
659
  pluginMethodsForClasses[className] = pluginMethodsForClass
498
- for method in pluginMethodsForClass:
499
- yield method
660
+ yield from pluginMethodsForClass
500
661
 
501
662
 
502
663
  def addPluginModule(name: str) -> dict[str, Any] | None:
@@ -505,23 +666,20 @@ def addPluginModule(name: str) -> dict[str, Any] | None:
505
666
  :param name: The name to search for
506
667
  :return: The module information dictionary, if added. Otherwise, None.
507
668
  """
508
- unloaded_arelle_plugins = discoverPluginEntryPoints(name)
509
- if len(unloaded_arelle_plugins) > 1:
510
- error_msg = f'Multiple pip installed plugins with name {name} in group arelle.plugin'
511
- logPluginTrace(error_msg, logging.ERROR)
512
- plugin_module_info = None
513
- if unloaded_arelle_plugins:
514
- plugin_module_info = entryPointToModuleInfo(unloaded_arelle_plugins[0])
515
- if not plugin_module_info or not plugin_module_info.get("name"):
516
- plugin_module_info = moduleModuleInfo(name)
517
- return addPluginModuleInfo(plugin_module_info)
669
+ entryPointRef = EntryPointRef.get(name)
670
+ pluginModuleInfo = None
671
+ if entryPointRef:
672
+ pluginModuleInfo = entryPointRef.createModuleInfo()
673
+ if not pluginModuleInfo or not pluginModuleInfo.get("name"):
674
+ pluginModuleInfo = moduleModuleInfo(moduleURL=name)
675
+ return addPluginModuleInfo(pluginModuleInfo)
518
676
 
519
677
 
520
678
  def reloadPluginModule(name):
521
679
  if name in pluginConfig["modules"]:
522
680
  url = pluginConfig["modules"][name].get("moduleURL")
523
681
  if url:
524
- moduleInfo = moduleModuleInfo(url, reload=True)
682
+ moduleInfo = moduleModuleInfo(moduleURL=url, reload=True)
525
683
  if moduleInfo:
526
684
  addPluginModule(url)
527
685
  return True
@@ -585,26 +743,180 @@ def addPluginModuleInfo(plugin_module_info: dict[str, Any]) -> dict[str, Any] |
585
743
  return plugin_module_info
586
744
 
587
745
 
588
- def entryPointToModuleInfo(entryPoint: EntryPoint) -> dict:
589
- """
590
- Given an EntryPoint instance, evaluates the plugin to retrieve a module information dictionary.
591
- :param entryPoint: EntryPoint instance
592
- :return: Module information dictionary
593
- """
594
- pluginUrl = entryPoint.load()
595
- return moduleModuleInfo(pluginUrl())
746
+ _entryPointRefCache: list[EntryPointRef] | None = None
747
+ _entryPointRefAliasCache: dict[str, list[EntryPointRef]] | None = None
748
+ _entryPointRefSearchTermEndings = [
749
+ '/__init__.py',
750
+ '.py'
751
+ '/'
752
+ ]
596
753
 
597
754
 
598
- def discoverPluginEntryPoints(name: str | None = None) -> list[EntryPoint]:
599
- """
600
- Retrieve entry point information. Optionally provide `name` to retrieve a specific entry point.
601
- :param name: Only retrieve entry points with the given name. May return multiple items.
602
- :return: List of EntryPoints
603
- """
604
- if sys.version_info < (3, 10):
605
- return [e for e in entry_points().get('arelle.plugin', []) if name is None or e.name == name]
606
- else:
607
- matches = entry_points(group='arelle.plugin')
608
- if name is not None:
609
- matches = matches.select(name=name)
610
- return list(matches)
755
+ @dataclass
756
+ class EntryPointRef:
757
+ aliases: set[str]
758
+ entryPoint: EntryPoint | None
759
+ moduleFilename: str | None
760
+ moduleInfo: dict | None
761
+
762
+ def createModuleInfo(self) -> dict | None:
763
+ """
764
+ Creates a module information dictionary from the entry point ref.
765
+ :return: A module inforomation dictionary
766
+ """
767
+ if self.entryPoint is not None:
768
+ return moduleModuleInfo(entryPoint=self.entryPoint)
769
+ return moduleModuleInfo(moduleURL=self.moduleFilename)
770
+
771
+ @staticmethod
772
+ def fromEntryPoint(entryPoint: EntryPoint) -> EntryPointRef | None:
773
+ """
774
+ Given an entry point, retrieves the subset of information from __pluginInfo__ necessary to
775
+ determine if the entry point should be imported as a plugin.
776
+ :param entryPoint:
777
+ :return:
778
+ """
779
+ pluginUrlFunc = entryPoint.load()
780
+ pluginUrl = pluginUrlFunc()
781
+ return EntryPointRef.fromFilepath(pluginUrl, entryPoint)
782
+
783
+ @staticmethod
784
+ def fromFilepath(filepath: str, entryPoint: EntryPoint | None = None) -> EntryPointRef | None:
785
+ """
786
+ Given a filepath, retrieves a subset of information from __pluginInfo__ necessary to
787
+ determine if the entry point should be imported as a plugin.
788
+ :param filepath: Path to plugin, can be a directory or .py filepath
789
+ :param entryPoint: Optional entry point information to include in aliases/moduleInfo
790
+ :return:
791
+ """
792
+ moduleFilename = _cntlr.webCache.getfilename(filepath)
793
+ if moduleFilename:
794
+ moduleFilename = normalizeModuleFilename(moduleFilename)
795
+ aliases = set()
796
+ if entryPoint:
797
+ aliases.add(entryPoint.name)
798
+ moduleInfo: dict | None = None
799
+ if moduleFilename:
800
+ moduleInfo = parsePluginInfo(moduleFilename, moduleFilename, entryPoint)
801
+ if moduleInfo is None:
802
+ return None
803
+ if "name" in moduleInfo:
804
+ aliases.add(moduleInfo["name"])
805
+ if "aliases" in moduleInfo:
806
+ aliases |= set(moduleInfo["aliases"])
807
+ return EntryPointRef(
808
+ aliases={EntryPointRef._normalizePluginSearchTerm(a) for a in aliases},
809
+ entryPoint=entryPoint,
810
+ moduleFilename=moduleFilename,
811
+ moduleInfo=moduleInfo,
812
+ )
813
+
814
+ @staticmethod
815
+ def discoverAll() -> list[EntryPointRef]:
816
+ """
817
+ Retrieve all plugin entry points, cached on first run.
818
+ :return: List of all discovered entry points.
819
+ """
820
+ global _entryPointRefCache
821
+ if _entryPointRefCache is None:
822
+ assert _pluginBase is not None
823
+ _entryPointRefCache = EntryPointRef._discoverBuiltIn([], cast(str, _pluginBase)) + EntryPointRef._discoverInstalled()
824
+ return _entryPointRefCache
825
+
826
+ @staticmethod
827
+ def _discoverBuiltIn(entryPointRefs: list[EntryPointRef], directory: str) -> list[EntryPointRef]:
828
+ """
829
+ Recursively retrieve all plugin entry points in the given directory.
830
+ :param entryPointRefs: Working list of entry point refs to append to.
831
+ :param directory: Directory to search for entry points within.
832
+ :return: List of discovered entry points.
833
+ """
834
+ for fileName in sorted(os.listdir(directory)):
835
+ if fileName in (".", "..", "__pycache__", "__init__.py", ".DS_Store", "site-packages"):
836
+ continue # Ignore these entries
837
+ filePath = os.path.join(directory, fileName)
838
+ if os.path.isdir(filePath):
839
+ EntryPointRef._discoverBuiltIn(entryPointRefs, filePath)
840
+ if os.path.isfile(filePath) and os.path.basename(filePath).endswith(".py"):
841
+ # If `filePath` references .py file directly, use it
842
+ moduleFilePath = filePath
843
+ elif os.path.isdir(filePath) and os.path.exists(initFilePath := os.path.join(filePath, "__init__.py")):
844
+ # Otherwise, if `filePath` is a directory containing `__init__.py`, use that
845
+ moduleFilePath = initFilePath
846
+ else:
847
+ continue
848
+ entryPointRef = EntryPointRef.fromFilepath(moduleFilePath)
849
+ if entryPointRef is not None:
850
+ entryPointRefs.append(entryPointRef)
851
+ return entryPointRefs
852
+
853
+ @staticmethod
854
+ def _discoverInstalled() -> list[EntryPointRef]:
855
+ """
856
+ Retrieve all installed plugin entry points.
857
+ :return: List of all discovered entry points.
858
+ """
859
+ entryPoints: list[EntryPoint]
860
+ if sys.version_info < (3, 10):
861
+ entryPoints = [e for e in entry_points().get('arelle.plugin', [])]
862
+ else:
863
+ entryPoints = list(entry_points(group='arelle.plugin'))
864
+ entryPointRefs = []
865
+ for entryPoint in entryPoints:
866
+ entryPointRef = EntryPointRef.fromEntryPoint(entryPoint)
867
+ if entryPointRef is not None:
868
+ entryPointRefs.append(entryPointRef)
869
+ return entryPointRefs
870
+
871
+ @staticmethod
872
+ def get(search: str) -> EntryPointRef | None:
873
+ """
874
+ Retrieve an entry point ref with a matching name or alias.
875
+ May return None of no matches are found.
876
+ Throws an exception if multiple entry point refs match the search term.
877
+ :param search: Only retrieve entry point matching the given search text.
878
+ :return: Matching entry point ref, if found.
879
+ """
880
+ entryPointRefs = EntryPointRef.search(search)
881
+ if len(entryPointRefs) == 0:
882
+ return None
883
+ elif len(entryPointRefs) > 1:
884
+ paths = [r.moduleFilename for r in entryPointRefs]
885
+ raise Exception(_('Multiple entry points matched search term "{}": {}').format(search, paths))
886
+ return entryPointRefs[0]
887
+
888
+ @staticmethod
889
+ def _normalizePluginSearchTerm(search: str) -> str:
890
+ """
891
+ Normalizes the given search term or searchable text by:
892
+ Making slashes consistent
893
+ Removing common endings
894
+ :param search: Search term or searchable text
895
+ :return: Normalized string
896
+ """
897
+ search = search.replace('\\', '/')
898
+ while True:
899
+ for ending in _entryPointRefSearchTermEndings:
900
+ if search.endswith(ending):
901
+ search = search[:-len(ending)]
902
+ break
903
+ return search.lower()
904
+
905
+ @staticmethod
906
+ def search(search: str) -> list[EntryPointRef] | None:
907
+ """
908
+ Retrieve entry point module information matching provided search text.
909
+ A map of aliases to matching entry points is cached on the first run.
910
+ :param search: Only retrieve entry points matching the given search text.
911
+ :return: List of matching module infos.
912
+ """
913
+ global _entryPointRefAliasCache
914
+ if _entryPointRefAliasCache is None:
915
+ entryPointRefAliasCache = defaultdict(list)
916
+ entryPointRefs = EntryPointRef.discoverAll()
917
+ for entryPointRef in entryPointRefs:
918
+ for alias in entryPointRef.aliases:
919
+ entryPointRefAliasCache[alias].append(entryPointRef)
920
+ _entryPointRefAliasCache = entryPointRefAliasCache
921
+ search = EntryPointRef._normalizePluginSearchTerm(search)
922
+ return _entryPointRefAliasCache.get(search, [])