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
@@ -1,3108 +1,28 @@
1
- '''
2
- loadFromOIM.py is an example of a plug-in that will load an extension taxonomy from OIM
3
- input (JSON, CSV or Excel bearing CSV) and optionally save an xBRL-XML instance thereof.
4
-
1
+ """
5
2
  See COPYRIGHT.md for copyright information.
3
+ """
6
4
 
7
- Example to run from web server:
8
-
9
- 1) POSTing excel in a zip, getting instance and log back in zip:
10
-
11
- curl -k -v -X POST "-HContent-type: application/zip" -T /Users/hermf/Documents/blahblah.xlsx.zip "localhost:8080/rest/xbrl/open?media=zip&file=WIP_DETAILED_3.xlsx&plugins=loadFromOIM&saveOIMinstance=myinstance.xbrl" -o out.zip
12
-
13
- 2) POSTing json within an archive of XII test cases and log and instance back in zip
14
-
15
- curl -k -v -X POST "-HContent-type: application/zip" -T test.zip "localhost:8080/rest/xbrl/open?media=zip&file=100-json/helloWorld.json&plugins=loadFromOIM&saveOIMinstance=myinstance.xbrl" -o out.zip
5
+ from typing import Any
16
6
 
17
-
18
- '''
19
- import os, sys, io, time, traceback, json, csv, logging, zipfile, datetime, isodate
20
- from math import isnan, log10
21
- from regex import compile as re_compile, match as re_match, sub as re_sub, DOTALL as re_DOTALL
22
- from lxml import etree
23
- from collections import defaultdict, OrderedDict
24
- from arelle.ModelDocument import Type, create as createModelDocument
25
- from arelle.ModelDtsObject import ModelResource
26
- from arelle import XbrlConst, ModelDocument, ModelXbrl, PackageManager, ValidateXbrlDimensions
27
- from arelle.ModelObject import ModelObject
28
- from arelle.PluginManager import pluginClassMethods
29
- from arelle.ModelValue import qname, dateTime, DateTime, DATETIME, yearMonthDuration, dayTimeDuration
30
- from arelle.PrototypeInstanceObject import DimValuePrototype
31
- from arelle.PythonUtil import attrdict, flattenToSet, strTruncate
32
- from arelle.UrlUtil import isHttpUrl, isAbsolute as isAbsoluteUri, isValidUriReference
7
+ from arelle.oim.Validate import validateOIM
8
+ from arelle.ValidateXbrl import ValidateXbrl
33
9
  from arelle.Version import authorLabel, copyrightLabel
34
- from arelle.XbrlConst import (xbrli, qnLinkLabel, standardLabelRoles, qnLinkReference, standardReferenceRoles,
35
- qnLinkPart, gen, link, defaultLinkRole, footnote, factFootnote, isStandardRole,
36
- conceptLabel, elementLabel, conceptReference, all as hc_all, notAll as hc_notAll,
37
- xhtml, qnXbrliDateItemType,
38
- dtrPrefixedContentItemTypes, dtrPrefixedContentTypes, dtrSQNameNamesItemTypes, dtrSQNameNamesTypes,
39
- lrrRoleHrefs, lrrArcroleHrefs)
40
- from arelle.XmlUtil import addChild, addQnameValue, copyIxFootnoteHtml, setXmlns
41
- from arelle.XmlValidateConst import VALID
42
- from arelle.XmlValidate import integerPattern, languagePattern, NCNamePattern, QNamePattern, validate as xmlValidate
43
- from arelle.ValidateXbrlCalcs import inferredDecimals, rangeValue
44
-
45
- nsOims = ("https://xbrl.org/2021",
46
- "http://www.xbrl.org/WGWD/YYYY-MM-DD",
47
- "https://www.xbrl.org/WGWD/YYYY-MM-DD",
48
- "http://www.xbrl.org/((~status_date_uri~))",
49
- "https://xbrl.org/((~status_date_uri~))"
50
- )
51
- nsOimCes = ("https://xbrl.org/2021/oim-common/error",
52
- "http://www.xbrl.org/WGWD/YYYY-MM-DD/oim-common/error",
53
- "http://www.xbrl.org/CR/2020-05-06/oim-common/error",
54
- "http://www.xbrl.org/((~status_date_uri~))/oim-common/error",
55
- "https://xbrl.org/((~status_date_uri~))/oim-common/error"
56
- )
57
- jsonDocumentTypes = (
58
- "https://xbrl.org/2021/xbrl-json",
59
- "http://www.xbrl.org/WGWD/YYYY-MM-DD/xbrl-json",
60
- "http://www.xbrl.org/YYYY-MM-DD/xbrl-json",
61
- "https://xbrl.org/((~status_date_uri~))/xbrl-json" # allows loading of XII "template" test cases without CI production
62
- )
63
- csvDocumentTypes = (
64
- "https://xbrl.org/2021/xbrl-csv",
65
- "http://www.xbrl.org/WGWD/YYYY-MM-DD/xbrl-csv",
66
- "http://xbrl.org/YYYY/xbrl-csv",
67
- "https://xbrl.org/((~status_date_uri~))/xbrl-csv" # allows loading of XII "template" test cases without CI production
68
- )
69
- csvDocinfoObjects = {"documentType", "namespaces", "taxonomy", "extends", "final", "linkTypes", "linkGroups"}
70
- csvExtensibleObjects = {"namespaces", "linkTypes", "linkGroups", "features", "final", "tableTemplates", "tables", "dimensions", "parameters"}
71
-
72
-
73
- reservedLinkTypesAndGroups = {
74
- "footnote": "http://www.xbrl.org/2003/arcrole/fact-footnote",
75
- "explanatoryFact": "http://www.xbrl.org/2009/arcrole/fact-explanatoryFact",
76
- "_": "http://www.xbrl.org/2003/role/link"
77
- }
78
- reservedLinkTypeAndGroupAliases = {
79
- "http://www.xbrl.org/2003/arcrole/fact-footnote": "footnote",
80
- "http://www.xbrl.org/2009/arcrole/fact-explanatoryFact": "explanatoryFact",
81
- "http://www.xbrl.org/2003/role/link": "_"
82
- }
83
-
84
-
85
- XLINKTYPE = "{http://www.w3.org/1999/xlink}type"
86
- XLINKLABEL = "{http://www.w3.org/1999/xlink}label"
87
- XLINKARCROLE = "{http://www.w3.org/1999/xlink}arcrole"
88
- XLINKFROM = "{http://www.w3.org/1999/xlink}from"
89
- XLINKTO = "{http://www.w3.org/1999/xlink}to"
90
- XLINKHREF = "{http://www.w3.org/1999/xlink}href"
91
- XMLLANG = "{http://www.w3.org/XML/1998/namespace}lang"
92
-
93
- JSONdocumentType = "http://www.xbrl.org/WGWD/YYYY-MM-DD/xbrl-json"
94
-
95
- NSReservedAliasURIs = {
96
- "xbrl": nsOims,
97
- "xs": (XbrlConst.xsd,),
98
- "enum2": XbrlConst.enum2s,
99
- # "oimce": nsOimCes,
100
- "xbrli": (XbrlConst.xbrli,),
101
- "xs": (XbrlConst.xsd,),
102
- "utr": (XbrlConst.utr,),
103
- "iso4217": (XbrlConst.iso4217,),
104
- #"xbrle": [ns + "/error" for ns in nsOims],
105
- #"xbrlxe": [ns + "/xbrl-xml/error" for ns in nsOims]
106
- }
107
- JSONNSReservedAliasURIs = {
108
- # xbrlje no longer reserved, issue #381
109
- # "xbrlje": [ns + "/xbrl-json/error" for ns in nsOims],
110
- }
111
- CSVNSReservedAliasURIs = {
112
- "xbrlce": [ns + "/xbrl-csv/error" for ns in nsOims],
113
- }
114
- JSONNSReservedURIAliases = {} # #381 no longer reserved - dict((ns + "/xbrl-json/error", "xbrlje") for ns in nsOims)
115
- CSVNSReservedURIAliases = dict((ns + "/xbrl-csv/error", "xbrlce") for ns in nsOims)
116
- NSReservedAliasURIPrefixes = { # for starts-with checking
117
- # "dtr-type": "http://www.xbrl.org/dtr/type/",
118
- }
119
- NSReservedURIAlias = {}
120
-
121
- OIMDefaultContextElement = "scenario"
122
- OIMReservedAliasURIs = {
123
- # "namespaces": NSReservedAliasURIs, -- generated at load time
124
- "linkTypes": reservedLinkTypesAndGroups,
125
- "linkGroups": reservedLinkTypesAndGroups
126
- }
127
- OIMReservedURIAlias = {
128
- #"namespaces": NSReservedURIAlias, -- generated at load time
129
- "linkTypes": reservedLinkTypeAndGroupAliases,
130
- "linkGroups": reservedLinkTypeAndGroupAliases
131
- }
132
-
133
- EMPTY_DICT = {}
134
- EMPTY_LIST = []
135
-
136
- DUPJSONKEY = "!@%duplicateKeys%@!"
137
- DUPJSONVALUE = "!@%duplicateValues%@!"
138
-
139
- UTF_7_16_Pattern = re_compile(r"(?P<utf16>(^([\x00][^\x00])+$)|(^([^\x00][\x00])+$))|(?P<utf7>^\s*\+AHs-)")
140
- UTF_7_16_Bytes_Pattern = re_compile(br"(?P<utf16>(^([\x00][^\x00])+$)|(^([^\x00][\x00])+$))|(?P<utf7>^\s*\+AHs-)")
141
- EBCDIC_Bytes_Pattern = re_compile(b"^[\x40\x4a-\x4f\x50\x5a-\x5f\x60-\x61\x6a-\x6f\x79-\x7f\x81-\x89\x8f\x91-\x99\xa1-\xa9\xb0\xba-\xbb\xc1-\xc9\xd1-\xd9\xe0\xe2-\xe9\xf0-\xf9\xff\x0a\x0d]+$")
142
- NEVER_EBCDIC_Bytes_Pattern = re_compile(b"[\x30-\x31\x3e\x41-\x49\x51-\x59\x62-\x69\x70-\x78\x80\x8a-\x8e\x90\x9a-\x9f\xa0\xaa-\xaf\xb1-\xb9\xbc-\xbf\xca-\xcf\xda-\xdf\xe1\xea-\xef\xfa-\xfe]")
143
- JSONmetadataPattern = re_compile(r"\s*\{.*\"documentInfo\"\s*:.*\}", re_DOTALL)
144
- NoCanonicalPattern = attrdict(match=lambda s: True)
145
- CanonicalFloatPattern = re_compile(r"^-?[0-9]\.[0-9]([0-9]*[1-9])?E-?([1-9][0-9]*|0)$|^-?INF$|^NaN$")
146
- CanonicalIntegerPattern = re_compile(r"^-?([1-9][0-9]*)?[0-9]$")
147
- CanonicalXmlTypePattern = {
148
- "boolean": re_compile("^true$|^false$"),
149
- "date": re_compile(r"-?[0-9]{4}-[0-9]{2}-[0-9]{2}Z?$"),
150
- "dateTime": re_compile(r"-?[0-9]{4}-[0-9]{2}-[0-9]{2}T([01][0-9]|20|21|22|23):[0-9]{2}:[0-9]{2}(\.[0-9]([0-9]*[1-9])?)?Z?$"),
151
- "XBRLI_DATEUNION": re_compile(r"-?[0-9]{4}-[0-9]{2}-[0-9]{2}Z?$|-?[0-9]{4}-[0-9]{2}-[0-9]{2}T([01][0-9]|20|21|22|23):[0-9]{2}:[0-9]{2}(\.[0-9]([0-9]*[1-9])?)?Z?$"),
152
- "time": re_compile(r"-?([01][0-9]|20|21|22|23):[0-9]{2}:[0-9]{2}(\.[0-9]([0-9]*[1-9])?)?Z?$"),
153
- "decimal": re_compile(r"^[-]?([1-9][0-9]*)?[0-9]\.[0-9]([0-9]*[1-9])?$"),
154
- "float": CanonicalFloatPattern,
155
- "double": CanonicalFloatPattern,
156
- "hexBinary": re_compile(r"^([0-9A-F][0-9A-F])*$"),
157
- "integer": CanonicalIntegerPattern,
158
- "language": re_compile(r"[a-z]{1,8}(-[a-z0-9]{1,8})*$"),
159
- "nonPositiveInteger": CanonicalIntegerPattern,
160
- "negativeInteger": CanonicalIntegerPattern,
161
- "long": CanonicalIntegerPattern,
162
- "int": CanonicalIntegerPattern,
163
- "short": CanonicalIntegerPattern,
164
- "byte": CanonicalIntegerPattern,
165
- "nonNegativeInteger": CanonicalIntegerPattern,
166
- "unsignedLong": CanonicalIntegerPattern,
167
- "unsignedInt": CanonicalIntegerPattern,
168
- "unsignedShort": CanonicalIntegerPattern,
169
- "unsignedByte": CanonicalIntegerPattern,
170
- "positiveInteger": CanonicalIntegerPattern,
171
- }
172
- IdentifierPattern = re_compile(
173
- "^[_A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]"
174
- r"[_\-"
175
- "\xB7A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040]*$")
176
- RowIdentifierPattern = re_compile(
177
- r"[_\-"
178
- "\xB7A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040]*$")
179
- PeriodPattern = re_compile(
180
- r"^-?[0-9]{4}-[0-9]{2}-[0-9]{2}T([01][0-9]|20|21|22|23):[0-9]{2}:[0-9]{2}(\.[0-9]([0-9]*[1-9])?)?Z?"
181
- r"(/-?[0-9]{4}-[0-9]{2}-[0-9]{2}T([01][0-9]|20|21|22|23):[0-9]{2}:[0-9]{2}(\.[0-9]([0-9]*[1-9])?)?Z?)?$"
182
- )
183
- PrefixedQName = re_compile(
184
- "[_A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]"
185
- r"[_\-\."
186
- "\xB7A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040]*:"
187
- "[_A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]"
188
- r"[_\-\."
189
- "\xB7A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040]*")
190
- SpecialValuePattern = re_compile("##|#empty$|#nil$|#none$")
191
- SQNamePattern = re_compile(
192
- "[_A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]"
193
- r"[_\-\."
194
- "\xB7A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040]*:"
195
- r"\S+")
196
- UnitPrefixedQNameSubstitutionChar = "\x07" # replaces PrefixedQName in unit pattern
197
- UnitPattern = re_compile(
198
- # QNames are replaced by \x07 in these expressions
199
- # numerator only (no parentheses)
200
- "(^\x07$)|(^\x07([*]\x07)+$)|"
201
- # numerator and optional denominator, with parentheses if more than one term in either
202
- "(^((\x07)|([(]\x07([*]\x07)+[)]))([/]((\x07)|([(]\x07([*]\x07)+[)])))?$)"
203
- )
204
- UrlInvalidPattern = re_compile(
205
- r"^[ \t\n\r]+[^ \t\n\r]*|.*[^ \t\n\r][ \t\n\r]+$|" # leading or trailing whitespace
206
- r".*[^ \t\n\r]([\t\n\r]+|[ \t\n\r]{2,})[^ \t\n\r]|" # embedded uncollapsed whitespace
207
- r".*%[^0-9a-fA-F]|.*%[0-9a-fA-F][^0-9a-fA-F]|.*#.*#" # invalid %nn or two ##s
208
- )
209
- WhitespacePattern = re_compile(r"[ \t\n\r]")
210
- WhitespaceUntrimmedPattern = re_compile(r"^[ \t\n\r]|.*[ \t\n\r]$")
211
-
212
- xlUnicodePattern = re_compile("_x([0-9A-F]{4})_")
213
-
214
- precisionZeroPattern = re_compile(r"^\s*0+\s*$")
215
- decimalsSuffixPattern = re_compile(r".*[0-9.][\r\n\t ]*d[\r\n\t ]*(0|-?[1-9][0-9]*|INF)[\r\n\t ]*$") # test starting 1 position before the d
216
-
217
- RegexPatternType = type(decimalsSuffixPattern)
218
-
219
- htmlBodyTemplate = "<body xmlns='http://www.w3.org/1999/xhtml'>\n{0}\n</body>\n"
220
- xhtmlTagPrefix = "{http://www.w3.org/1999/xhtml}"
221
- DimensionsKeyPattern = re_compile(r"^(concept|entity|period|unit|language|(\w+:\w+))$")
222
-
223
- nonDiscoveringXmlInstanceElements = {qname(link, "roleRef"), qname(link, "arcroleRef")}
224
-
225
- UNSUPPORTED_DATA_TYPES = dtrPrefixedContentItemTypes + (
226
- qname(xbrli,"fractionItemType"), )
227
-
228
- # CSV Files
229
- CSV_PARAMETER_FILE = 1
230
- CSV_FACTS_FILE = 2
231
- CSV_HAS_HEADER_ROW = True
232
-
233
- # allowed duplicates settings
234
- NONE = 1
235
- COMPLETE = 2
236
- CONSISTENT = 3
237
- ALL = 4
238
- AllowedDuplicatesFeatureValues = {"none": NONE, "complete": COMPLETE, "consistent": CONSISTENT, "all": ALL}
239
- DisallowedDescription = {NONE: "Disallowed", COMPLETE: "Non-complete", CONSISTENT: "Inconsistent", ALL: "Allowed"}
240
-
241
- class SQNameType:
242
- pass # fake class for detecting SQName type in JSON structure check
243
-
244
- class QNameType:
245
- pass # fake class for detecting QName type in JSON structure check
246
-
247
- class LangType:
248
- pass
249
-
250
- class URIType:
251
- pass
252
-
253
- class IdentifierType:
254
- pass
255
-
256
- class NoRecursionCheck:
257
- pass
258
-
259
- class CheckPrefix:
260
- pass
261
-
262
- class KeyIsNcName:
263
- pass
264
-
265
-
266
- UnrecognizedDocMemberTypes = {
267
- "/documentInfo": dict,
268
- "/documentInfo/documentType": str,
269
- }
270
- UnrecognizedDocRequiredMembers = {
271
- "/": {"documentInfo"},
272
- "/documentInfo/": {"documentType","taxonomy"},
273
- }
274
-
275
- JsonMemberTypes = {
276
- # keys are json pointer with * meaning any id, and *:* meaning any SQName or QName, for array no index is used
277
- # report
278
- "/documentInfo": dict,
279
- "/facts": dict,
280
- "/*:*": (int,bool,str,dict,list,type(None),NoRecursionCheck,CheckPrefix), # custom extensions
281
- # documentInfo
282
- "/documentInfo/baseURL": URIType,
283
- "/documentInfo/documentType": str,
284
- "/documentInfo/features": dict,
285
- "/documentInfo/features/*:*": (int,float,bool,str,type(None)),
286
- "/documentInfo/namespaces": dict,
287
- "/documentInfo/namespaces/*": URIType,
288
- "/documentInfo/linkTypes": dict,
289
- "/documentInfo/linkTypes/*": str,
290
- "/documentInfo/linkGroups": dict,
291
- "/documentInfo/linkGroups/*": str,
292
- "/documentInfo/taxonomy": list,
293
- "/documentInfo/taxonomy/": str,
294
- "/documentInfo/*:*": (int,float,bool,str,dict,list,type(None),NoRecursionCheck,CheckPrefix), # custom extensions
295
- # facts
296
- "/facts/*": dict,
297
- "/facts/*/value": (str,type(None)),
298
- "/facts/*/decimals": int,
299
- "/facts/*/dimensions": dict,
300
- "/facts/*/links": dict,
301
- "/facts/*/links/*": dict,
302
- "/facts/*/links/*/*": list,
303
- "/facts/*/links/*/*/": str,
304
- # dimensions
305
- "/facts/*/dimensions/concept": QNameType,
306
- "/facts/*/dimensions/entity": SQNameType,
307
- "/facts/*/dimensions/period": str,
308
- "/facts/*/dimensions/unit": str,
309
- "/facts/*/dimensions/language": LangType,
310
- "/facts/*/dimensions/noteId": str,
311
- "/facts/*/dimensions/*:*": (str,type(None)),
312
- # custom properties on fact are unchecked
313
- "/facts/*/*:*": (int,float,bool,str,dict,list,type(None),NoRecursionCheck,CheckPrefix), # custom extensions
314
- }
315
- JsonRequiredMembers = {
316
- "/": {"documentInfo"},
317
- "/documentInfo/": {"documentType","taxonomy"},
318
- "/facts/*/": {"value","dimensions"},
319
- "/facts/*/dimensions/": {"concept"}
320
- }
321
-
322
- CsvMemberTypes = {
323
- # report
324
- "/documentInfo": dict,
325
- "/tableTemplates": dict,
326
- "/tables": dict,
327
- "/parameters": dict,
328
- "/parameters/*": str,
329
- "/parameterURL": str,
330
- "/dimensions": dict,
331
- "/decimals": (int,str),
332
- "/links": dict,
333
- "/*:*": (int,float,bool,str,dict,list,type(None),NoRecursionCheck,CheckPrefix), # custom extensions
334
- # documentInfo
335
- "/documentInfo/baseURL": URIType,
336
- "/documentInfo/documentType": str,
337
- "/documentInfo/features": dict,
338
- "/documentInfo/features/*:*": (int,float,bool,str,type(None)),
339
- "/documentInfo/final": dict,
340
- "/documentInfo/namespaces": dict,
341
- "/documentInfo/namespaces/*": URIType,
342
- "/documentInfo/linkTypes": dict,
343
- "/documentInfo/linkTypes/*": str,
344
- "/documentInfo/linkGroups": dict,
345
- "/documentInfo/linkGroups/*": str,
346
- "/documentInfo/taxonomy": list,
347
- "/documentInfo/taxonomy/": str,
348
- "/documentInfo/extends": list,
349
- "/documentInfo/extends/": URIType,
350
- "/documentInfo/*:*": (int,float,bool,str,dict,list,type(None),NoRecursionCheck,CheckPrefix), # custom extensions
351
- # documentInfo/final
352
- "/documentInfo/final/namespaces": bool,
353
- "/documentInfo/final/taxonomy": bool,
354
- "/documentInfo/final/linkTypes": bool,
355
- "/documentInfo/final/linkGroups": bool,
356
- "/documentInfo/final/features": bool,
357
- "/documentInfo/final/tableTemplates": bool,
358
- "/documentInfo/final/tables": bool,
359
- "/documentInfo/final/dimensions": bool,
360
- "/documentInfo/final/final": bool,
361
- "/documentInfo/final/parameters": bool,
362
- "/documentInfo/final/parameterURL": bool,
363
- # table templates
364
- "/tableTemplates/*": dict,
365
- "/tableTemplates/*/rowIdColumn": str,
366
- "/tableTemplates/*/columns": dict,
367
- "/tableTemplates/*/decimals": (int,str),
368
- "/tableTemplates/*/dimensions": dict,
369
- "/tableTemplates/*:*": (int,float,bool,str,dict,list,type(None),NoRecursionCheck,CheckPrefix), # custom extensions
370
- "/tableTemplates/*/dimensions/concept": str,
371
- "/tableTemplates/*/dimensions/entity": str,
372
- "/tableTemplates/*/dimensions/period": str,
373
- "/tableTemplates/*/dimensions/unit": str,
374
- "/tableTemplates/*/dimensions/language": str,
375
- "/tableTemplates/*/dimensions/*:*": str,
376
- "/tableTemplates/*/dimensions/$*": str,
377
- #"/tableTemplates/*/transposed": bool,
378
- # columns
379
- "/tableTemplates/*/columns/*": dict,
380
- "/tableTemplates/*/columns/*/comment": bool,
381
- "/tableTemplates/*/columns/*/decimals": (int,str),
382
- "/tableTemplates/*/columns/*/dimensions": dict,
383
- "/tableTemplates/*/columns/*/*:*": (int,float,bool,str,dict,list,type(None),NoRecursionCheck,CheckPrefix), # custom extensions
384
- # dimensions (column)
385
- "/tableTemplates/*/columns/*/dimensions/concept": str,
386
- "/tableTemplates/*/columns/*/dimensions/entity": str,
387
- "/tableTemplates/*/columns/*/dimensions/period": str,
388
- "/tableTemplates/*/columns/*/dimensions/unit": str,
389
- "/tableTemplates/*/columns/*/dimensions/language": str,
390
- "/tableTemplates/*/columns/*/dimensions/*:*": str,
391
- "/tableTemplates/*/columns/*/dimensions/$*": str,
392
- # property groups (column)
393
- "/tableTemplates/*/columns/*/propertiesFrom": list,
394
- "/tableTemplates/*/columns/*/propertiesFrom/": str,
395
- "/tableTemplates/*/columns/*/propertyGroups": dict,
396
- "/tableTemplates/*/columns/*/propertyGroups/*": dict,
397
- "/tableTemplates/*/columns/*/propertyGroups/*/decimals": (int,str),
398
- "/tableTemplates/*/columns/*/propertyGroups/*/dimensions": dict,
399
- "/tableTemplates/*/columns/*/propertyGroups/*/dimensions/concept": str,
400
- "/tableTemplates/*/columns/*/propertyGroups/*/dimensions/entity": str,
401
- "/tableTemplates/*/columns/*/propertyGroups/*/dimensions/period": str,
402
- "/tableTemplates/*/columns/*/propertyGroups/*/dimensions/unit": str,
403
- "/tableTemplates/*/columns/*/propertyGroups/*/dimensions/language": str,
404
- "/tableTemplates/*/columns/*/propertyGroups/*/dimensions/*:*": str,
405
- "/tableTemplates/*/columns/*/propertyGroups/*/dimensions/$*": str,
406
- # dimensions (top level)
407
- "/dimensions/concept": str,
408
- "/dimensions/entity": str,
409
- "/dimensions/period": str,
410
- "/dimensions/unit": str,
411
- "/dimensions/language": str,
412
- "/dimensions/noteId": str,
413
- "/dimensions/*:*": str,
414
- "/dimensions/$*": str,
415
- # tables
416
- "/tables/*": dict,
417
- "/tables/*/url": str,
418
- "/tables/*/template": str,
419
- "/tables/*/optional": bool,
420
- "/tables/*/parameters": dict,
421
- "/tables/*/parameters/*": str,
422
- "/tables/*/*:*": (int,float,bool,str,dict,list,type(None),NoRecursionCheck,CheckPrefix), # custom extensions
423
- # links
424
- "/links/*": (dict,KeyIsNcName),
425
- # link group
426
- "/links/*/*": (dict,KeyIsNcName),
427
- # fact links
428
- "/links/*/*/*": list,
429
- # fact IDs
430
- "/links/*/*/*/*": str,
431
- }
432
- CsvRequiredMembers = {
433
- "/": {"documentInfo"},
434
- "/documentInfo/": {"documentType"},
435
- "/tableTemplates/*/": {"columns"},
436
- "/tables/*/": {"url"}
437
- }
438
- EMPTY_SET = set()
439
-
440
- def jsonGet(tbl, key, default=None):
441
- if isinstance(tbl, dict):
442
- return tbl.get(key, default)
443
- return default
444
-
445
- # singleton special values
446
- class Singleton(str):
447
- def __init__(self, value):
448
- self.value = value
449
- def __str__(self):
450
- return self.value
451
-
452
- EMPTY_CELL = Singleton("")
453
- NONE_CELL = Singleton("")
454
- INVALID_REFERENCE_TARGET = Singleton("")
455
-
456
- def csvCellValue(cellValue):
457
- # CSV table in Appendix A
458
- if cellValue == "#nil": # nil value
459
- return None
460
- elif cellValue == "": # empty cell
461
- return EMPTY_CELL
462
- elif cellValue == "#none":
463
- return NONE_CELL
464
- elif cellValue == "#empty": # empty string
465
- return ""
466
- elif isinstance(cellValue, str) and cellValue.startswith("#"):
467
- if cellValue.startswith("##"):
468
- return cellValue[1:]
469
- else:
470
- raise OIMException("xbrlce:unknownSpecialValue",
471
- _("Unknown special value %(specialValue)s"),
472
- specialValue=cellValue)
473
- else:
474
- return cellValue
475
-
476
- def xlUnicodeChar(match):
477
- return chr(int(match.group(1), 16))
478
-
479
- def xlValue(cell): # excel values may have encoded unicode, such as _0000D_
480
- v = cell.value
481
- if isinstance(v, str):
482
- v = xlUnicodePattern.sub(xlUnicodeChar, v).replace('\r\n','\n').replace('\r','\n')
483
- elif v is None:
484
- v = ""
485
- elif isinstance(v, float):
486
- return str(round(v, 14)) # Deal with general numbers which may be imprecise
487
- else:
488
- v = str(v)
489
- return csvCellValue(v)
490
-
491
- def parseMetadataCellValues(metadataTable):
492
- for dimName in metadataTable.keys():
493
- dimValue = metadataTable[dimName]
494
- # CSV table in Appendix A (similar to "cellValue"
495
- if dimValue is None or dimValue == "#nil":
496
- metadataTable[dimName] = None
497
- elif dimValue == "" and dimName != "period": # empty cell except for period
498
- metadataTable[dimName] = EMPTY_CELL
499
- elif dimValue == "#none":
500
- metadataTable[dimName] = NONE_CELL
501
- elif isinstance(dimValue, str) and dimValue.startswith("##"):
502
- metadataTable[dimName] = dimValue[1:]
503
-
504
- def xlTrimHeaderRow(row):
505
- numEmptyCellsAtEndOfRow = 0
506
- for i in range(len(row)-1, -1, -1):
507
- if row[i] in (None, ""):
508
- numEmptyCellsAtEndOfRow += 1
509
- else:
510
- break
511
- if numEmptyCellsAtEndOfRow:
512
- return row[:-numEmptyCellsAtEndOfRow]
513
- return row
514
-
515
- class OIMException(Exception):
516
- def __init__(self, code=None, message=None, **kwargs):
517
- self.code = code
518
- self.message = message
519
- self.msgArgs = kwargs
520
- self.args = ( self.__repr__(), )
521
- def __repr__(self):
522
- if self.code and self.message:
523
- return _('[{0}] exception {1}').format(self.code, self.message % self.msgArgs)
524
- else:
525
- return "Errors noted in log"
526
-
527
- class NotOIMException(Exception):
528
- def __init__(self, **kwargs):
529
- self.args = ( self.__repr__(), )
530
- def __repr__(self):
531
- return _('[NotOIM] not an OIM document')
532
-
533
- class FactProduced():
534
- def clear(self):
535
- self.modelFact = None
536
- self.dimensionsUsed = set()
537
- self.invalidReferenceTarget = None
538
-
539
- PER_ISO = 0
540
- PER_INCLUSIVE_DATES = 1
541
- PER_SINGLE_DAY = 2
542
- PER_MONTH = 3
543
- PER_YEAR = 4
544
- PER_QTR = 5
545
- PER_HALF = 6
546
- PER_WEEK = 7
547
- ONE_DAY = dayTimeDuration("P1D")
548
- ONE_MONTH = yearMonthDuration("P1M")
549
- ONE_YEAR = yearMonthDuration("P1Y")
550
- ONE_QTR = yearMonthDuration("P3M")
551
- ONE_HALF = yearMonthDuration("P6M")
552
-
553
- periodForms = ((PER_ISO, re_compile("([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(Z|[+-][0-2][0-9]([:]?)[0-5][0-9]+)?(/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2})?(Z|[+-][0-2][0-9]([:]?)[0-5][0-9]+)?)$")),
554
- (PER_INCLUSIVE_DATES, re_compile("([0-9]{4}-[0-9]{2}-[0-9]{2})[.][.]([0-9]{4}-[0-9]{2}-[0-9]{2})$")),
555
- (PER_SINGLE_DAY, re_compile("([0-9]{4}-[0-9]{2}-[0-9]{2})(@(start|end))?$")),
556
- (PER_MONTH, re_compile("([0-9]{4}-[0-9]{2})(@(start|end))?$")),
557
- (PER_YEAR, re_compile("([0-9]{4})(@(start|end))?$")),
558
- (PER_QTR, re_compile("([0-9]{4})Q([1-4])(@(start|end))?$")),
559
- (PER_HALF, re_compile("([0-9]{4})H([1-2])(@(start|end))?$")),
560
- (PER_WEEK, re_compile("([0-9]{4}W[1-5]?[0-9])(@(start|end))?$")))
561
-
562
- def csvPeriod(cellValue, startOrEnd=None):
563
- if cellValue is EMPTY_CELL or cellValue is NONE_CELL:
564
- return NONE_CELL # Forever period (absent in xBRL-JSON)
565
- if cellValue is None: # #nil is not valid for date
566
- return cellValue # stays None
567
- isoDuration = None
568
- for perType, perFormMatch in periodForms:
569
- m = perFormMatch.match(cellValue)
570
- if m:
571
- try:
572
- if perType == PER_ISO:
573
- if not m.group(4) and startOrEnd: # instant date
574
- return "referenceTargetNotDuration"
575
- isoDuration = cellValue
576
- startendSuffixGroup = 0
577
- elif perType == PER_INCLUSIVE_DATES:
578
- isoDuration = "{}/{}".format(dateTime(m.group(1)), dateTime(m.group(2)) + ONE_DAY)
579
- startendSuffixGroup = 0
580
- elif perType == PER_SINGLE_DAY:
581
- isoDuration = "{}/{}".format(dateTime(m.group(1)), dateTime(m.group(1)) + ONE_DAY)
582
- startendSuffixGroup = 3
583
- elif perType == PER_MONTH:
584
- moStart = dateTime(m.group(1) + "-01")
585
- isoDuration = "{}/{}".format(moStart, moStart + ONE_MONTH)
586
- startendSuffixGroup = 3
587
- elif perType == PER_YEAR:
588
- yrStart = dateTime(m.group(1) + "-01-01")
589
- isoDuration = "{}/{}".format(yrStart, yrStart + ONE_YEAR)
590
- startendSuffixGroup = 3
591
- elif perType == PER_QTR:
592
- qtrStart = dateTime(m.group(1) + "-{:02}-01".format(int(m.group(2))*3 - 2))
593
- isoDuration = "{}/{}".format(qtrStart, qtrStart + ONE_QTR)
594
- startendSuffixGroup = 4
595
- elif perType == PER_HALF:
596
- qtrStart = dateTime(m.group(1) + "-{:02}-01".format(int(m.group(2))*6 - 5))
597
- isoDuration = "{}/{}".format(qtrStart, qtrStart + ONE_HALF)
598
- startendSuffixGroup = 4
599
- elif perType == PER_WEEK:
600
- weekStart = dateTime(isodate.parse_date(m.group(1)))
601
- isoDuration = "{}T00:00:00/{}T00:00:00".format(weekStart, weekStart + datetime.timedelta(7))
602
- startendSuffixGroup = 3
603
- if startendSuffixGroup and m.group(startendSuffixGroup):
604
- if startOrEnd:
605
- # period specifier is being applied to an instant date
606
- return "referenceTargetNotDuration"
607
- startOrEnd = m.group(startendSuffixGroup)
608
- except ValueError:
609
- return None
610
- if isoDuration:
611
- if startOrEnd == "start":
612
- return isoDuration.partition("/")[0]
613
- elif startOrEnd == "end":
614
- return isoDuration.partition("/")[2]
615
- return isoDuration
616
- return None
617
-
618
- # no longer used because transpose is not supported
619
- def transposer(rowIterator, default=""):
620
- cells = [row for row in rowIterator]
621
- if cells:
622
- colsCount = max(len(row) for row in cells)
623
- rowsCount = len(cells)
624
- for colIndex in range(colsCount):
625
- yield [(cells[rowIndex][colIndex] if colIndex < len(cells[colIndex]) else default)
626
- for rowIndex in range(rowsCount)]
627
-
628
- def idDeduped(modelXbrl, id):
629
- for i in range(99999):
630
- if i == 0:
631
- candidateId = id
632
- else:
633
- candidateId = "{}.{}".format(id, i)
634
- if candidateId not in modelXbrl.modelDocument.idObjects:
635
- return candidateId
636
- return None
637
-
638
- def oimEquivalentFacts(f1, f2):
639
- if f1.context is None or f1.concept is None:
640
- return False # need valid context and concept for v-Equality of nonTuple
641
- if f1.isNil:
642
- return f2.isNil
643
- if f2.isNil:
644
- return False
645
- if not f1.context.isEqualTo(f2.context):
646
- return False
647
- elif type(f1.xValue) == type(f2.xValue):
648
- if f1.concept.isLanguage and f2.concept.isLanguage and f1.xValue is not None and f2.xValue is not None:
649
- return f1.xValue.lower() == f2.xValue.lower() # required to handle case insensitivity
650
- if isinstance(f1.xValue, DateTime): # with/without time makes values unequal
651
- return f1.xValue.dateOnly == f2.xValue.dateOnly and f1.xValue == f2.xValue
652
- return f1.xValue == f2.xValue # required to handle date/time with 24 hrs.
653
- return f1.value == f2.value
654
-
655
- def checkForDuplicates(modelXbrl, allowedDups, footnoteIDs):
656
- # intended to be use after loading OIM or possibly in future for xBRL-XML
657
- if allowedDups != ALL:
658
- factForConceptContextUnitHash = defaultdict(list)
659
- for f in modelXbrl.factsInInstance:
660
- if (f.isNil or getattr(f,"xValid", 0) >= 4) and f.context is not None and f.concept is not None and f.concept.type is not None:
661
- factForConceptContextUnitHash[f.conceptContextUnitHash].append(f)
662
- aspectEqualFacts = defaultdict(dict) # dict [(qname,lang)] of dict(cntx,unit) of [fact, fact]
663
- decVals = {}
664
- for hashEquivalentFacts in factForConceptContextUnitHash.values():
665
- if len(hashEquivalentFacts) > 1:
666
- for f in hashEquivalentFacts: # check for hash collision by value checks on context and unit
667
- cuDict = aspectEqualFacts[(f.qname,
668
- (f.xmlLang or "").lower() if f.concept.type.isWgnStringFactType else None)]
669
- _matched = False
670
- for (_cntx,_unit),fList in cuDict.items():
671
- if (((_cntx is None and f.context is None) or (f.context is not None and f.context.isEqualTo(_cntx))) and
672
- ((_unit is None and f.unit is None) or (f.unit is not None and f.unit.isEqualTo(_unit)))):
673
- _matched = True
674
- fList.append(f)
675
- break
676
- if not _matched:
677
- cuDict[(f.context,f.unit)] = [f]
678
- for cuDict in aspectEqualFacts.values(): # dups by qname, lang
679
- for fList in cuDict.values(): # dups by equal-context equal-unit
680
- if len(fList) > 1:
681
- f0 = fList[0]
682
- if allowedDups == NONE:
683
- _inConsistent = True
684
- elif allowedDups == CONSISTENT and f0.concept.isNumeric:
685
- if any(f.isNil for f in fList):
686
- _inConsistent = not all(f.isNil for f in fList)
687
- else: # not all have same decimals
688
- _d = inferredDecimals(f0)
689
- _v = f0.xValue
690
- _inConsistent = isnan(_v) # NaN is incomparable, always makes dups inconsistent
691
- decVals[_d] = _v
692
- aMax, bMin, _inclA, _inclB = rangeValue(_v, _d)
693
- for f in fList[1:]:
694
- _d = inferredDecimals(f)
695
- _v = f.xValue
696
- if isnan(_v) or _inConsistent: # may have been inconsistent from f0.value
697
- _inConsistent = True
698
- break
699
- if _d in decVals:
700
- _inConsistent |= _v != decVals[_d]
701
- else:
702
- decVals[_d] = _v
703
- a, b, _inclA, _inclB = rangeValue(_v, _d)
704
- if a > aMax: aMax = a
705
- if b < bMin: bMin = b
706
- if not _inConsistent:
707
- _inConsistent = (bMin < aMax)
708
- decVals.clear()
709
- else: # includes COMPLETE
710
- _inConsistent = any(not oimEquivalentFacts(f0, f) for f in fList[1:])
711
- if _inConsistent:
712
- modelXbrl.error("oime:disallowedDuplicateFacts",
713
- "%(disallowance)s duplicate fact values %(element)s: %(values)s, %(contextIDs)s.",
714
- modelObject=fList, disallowance=DisallowedDescription[allowedDups], element=f0.qname,
715
- contextIDs=", ".join(sorted(set(f.contextID for f in fList))),
716
- values=", ".join(strTruncate(f.value,64) for f in fList))
717
- aspectEqualFacts.clear()
718
- del factForConceptContextUnitHash, aspectEqualFacts
719
-
720
- ''' impossible to have dup footnotes (?)
721
- aspectEqualFootnotes = defaultdict(list) # dict [lang] of footnotes
722
- for footnoteID in footnoteIDs:
723
- f = modelXbrl.modelDocument.idObjects[footnoteID]
724
- aspectEqualFootnotes[f.xmlLang.lower()].append(f)
725
- for lang, footnotes in aspectEqualFootnotes.items():
726
- fByValue = sorted(footnotes, key=lambda f: f.viewText())
727
- lenF = len(fByValue)
728
- for i, f in enumerate(fByValue):
729
- if i == 0:
730
- fText = f.viewText()
731
- else:
732
- fText = fNext
733
- if i < lenF - 1:
734
- f2 = fByValue[i+1]
735
- fNext = f2.viewText()
736
- if fText == fNext:
737
- modelXbrl.error("oime:disallowedDuplicateFacts",
738
- "%(disallowance)s duplicate footnote ids %(IDs)s: value: %(value)s.",
739
- modelObject=(f, f2), disallowance=DisallowedDescription[allowedDups],
740
- IDs="{}, {}".format(f.id, f2.id),
741
- value=fText[:64])
742
- del aspectEqualFootnotes
743
- '''
744
-
745
- def getTaxonomyContextElement(modelXbrl):
746
- # https://www.xbrl.org/Specification/xbrl-xml/REC-2021-10-13/xbrl-xml-REC-2021-10-13.html#sec-dimensions
747
- # The spec states that if in the DTS:
748
- # 1. neither segment nor scenario is present, scenario is used.
749
- # 2. segment is present and scenario is not, segment is used.
750
- # 3. scenario is present and segment is not, scenario is used.
751
- # 4. segment and scenario are present and facts are valid against both of them, scenario is used.
752
- # 5. segment and scenario are present and facts are only valid against scenario, scenario is used.
753
- # 6. segment and scenario are present and facts are only valid against segment, segment is used.
754
- # 7. segment and scenario are present and facts are invalid against both, the choice is made arbitrarily.
755
- # We don't yet inspect dimensional validity and therefore incorrectly use scenario in case 6.
756
- taxonomyContextRefTypes = {
757
- modelRelationship.contextElement
758
- for hasHypercubeRelationship in (XbrlConst.all, XbrlConst.notAll)
759
- for modelRelationship in modelXbrl.relationshipSet(hasHypercubeRelationship).modelRelationships
760
- }
761
- return taxonomyContextRefTypes.pop() if len(taxonomyContextRefTypes) == 1 else OIMDefaultContextElement
762
-
763
- def loadFromOIM(cntlr, error, warning, modelXbrl, oimFile, mappedUri):
764
- from openpyxl import load_workbook
765
- from openpyxl.cell import Cell
766
- from arelle import ModelDocument, ModelXbrl, XmlUtil
767
- from arelle.ModelDocument import ModelDocumentReference
768
- from arelle.ModelValue import qname
769
-
770
- _return = None # modelDocument or an exception
771
-
772
- try:
773
- currentAction = "initializing"
774
- startingErrorCount = len(modelXbrl.errors) if modelXbrl else 0
775
- startedAt = time.time()
776
-
777
- currentAction = "determining file type"
778
- isJSON = False
779
- # isCSV means metadata loaded from separate JSON file (but instance data can be in excel or CSV)
780
- isCSV = False # oimFile.endswith(".csv") # this option is not currently supported
781
- instanceFileName = os.path.splitext(oimFile)[0] + ".xbrl"
782
-
783
- currentAction = "loading and parsing OIM file"
784
- loadDictErrors = []
785
- def openCsvReader(csvFilePath, fileType):
786
- _file = modelXbrl.fileSource.file(csvFilePath, binary=True)[0]
787
- bytes = _file.read(16) # test encoding
788
- try:
789
- m = EBCDIC_Bytes_Pattern.match(bytes)
790
- if m and not NEVER_EBCDIC_Bytes_Pattern.findall(bytes):
791
- raise OIMException("xbrlce:invalidCSVFileFormat",
792
- _("CSV file MUST use utf-8 encoding: %(file)s, appears to be EBCDIC"),
793
- file=csvFilePath)
794
- m = UTF_7_16_Bytes_Pattern.match(bytes)
795
- if m:
796
- raise OIMException("xbrlce:invalidCSVFileFormat",
797
- _("CSV file MUST use utf-8 encoding: %(file)s, appears to be %(encoding)s"),
798
- file=csvFilePath, encoding=m.lastgroup)
799
- _file.close()
800
- except UnicodeDecodeError as ex:
801
- raise OIMException("xbrlce:invalidCSVFileFormat",
802
- _("CSV file MUST use utf-8 encoding: %(file)s, appears to be %(encoding)s"),
803
- file=csvFilePath, encoding=m.lastgroup)
804
- _file = modelXbrl.fileSource.file(csvFilePath, encoding='utf-8-sig')[0]
805
- if CSV_HAS_HEADER_ROW:
806
- try:
807
- chars = _file.read(1024)
808
- _dialect = csv.Sniffer().sniff(chars, delimiters=[',', '\t', ';', '|']) # also check for disallowed potential separators
809
- if _dialect.lineterminator not in ("\r", "\n", "\r\n"):
810
- raise OIMException("xbrlce:invalidCSVFileFormat",
811
- _("CSV line ending is not CR, LF or CR LF, file %(file)s"),
812
- file=csvFilePath)
813
- if _dialect.delimiter not in (","):
814
- raise OIMException({CSV_PARAMETER_FILE: "xbrlce:invalidParameterCSVFile",
815
- CSV_FACTS_FILE: "xbrlce:invalidHeaderValue"}[fileType],
816
- _("CSV deliminator %(deliminator)s is not comma: file %(file)s"),
817
- file=csvFilePath, deliminator=repr(_dialect.delimiter))
818
- except csv.Error as ex:
819
- # possibly can't br sniffed because there's only one column in the rows
820
- _dialect = None
821
- for char in chars:
822
- if char in (",", "\n", "\r"):
823
- _dialect = "excel"
824
- break
825
- elif char == "\t":
826
- _dialect = "excel-tab"
827
- break
828
- if not _dialect:
829
- raise OIMException("xbrlce:invalidCSVFileFormat",
830
- _("CSV file %(file)s: %(error)s"),
831
- file=csvFilePath, error=str(ex))
832
- except UnicodeDecodeError as ex:
833
- raise OIMException("xbrlce:invalidCSVFileFormat",
834
- _("CSV file must use utf-8 encoding %(file)s: %(error)s"),
835
- file=csvFilePath, error=str(ex))
836
- _file.seek(0)
837
- else:
838
- # check for comma or tab in first line
839
- _dialect = "excel" # fallback if no first line tab is determinable
840
- for char in _file.read(1024):
841
- if char in (",", "\n", "\r", ";", "|"): # ;, | force invalid parameter file detection
842
- _dialect = "excel"
843
- break
844
- elif char == "\t": # only way to sniff first row deliminator if value contains SQName semicolon
845
- _dialect = "excel-tab"
846
- break
847
- _file.seek(0)
848
- return csv.reader(_file, _dialect)
849
-
850
- def ldError(msgCode, msgText, **kwargs):
851
- loadDictErrors.append((msgCode, msgText, kwargs))
852
- def loadDict(keyValuePairs):
853
- _dict = OrderedDict() # preserve fact order in resulting instance
854
- _valueKeyDict = {}
855
- for key, value in keyValuePairs:
856
- if isinstance(value, dict):
857
- if key in ("namespaces", "linkTypes", "linkGroups"):
858
- normalizedDict = OrderedDict()
859
- normalizedValueKeyDict = {}
860
- if DUPJSONKEY in value:
861
- normalizedDict[DUPJSONKEY] = value[DUPJSONKEY]
862
- if DUPJSONVALUE in value:
863
- normalizedDict[DUPJSONVALUE] = value[DUPJSONVALUE]
864
- for _key, _value in value.items():
865
- if not isinstance(_value, str):
866
- continue # skip dup key/value entries
867
- # _key = _key.strip() # per !178 keys have only normalized values, don't normalize key
868
- # _value = _value.strip()
869
- if _key in normalizedDict: # don't put the duplicate in the dictionary but report it as error
870
- if DUPJSONKEY not in normalizedDict:
871
- normalizedDict[DUPJSONKEY] = []
872
- normalizedDict[DUPJSONKEY].append((_key, _value, normalizedDict[_key]))
873
- else: # do put into dictionary, only report if it's a map object
874
- normalizedDict[_key] = _value
875
- if _value in normalizedValueKeyDict:
876
- if DUPJSONVALUE not in normalizedDict:
877
- normalizedDict[DUPJSONVALUE] = []
878
- normalizedDict[DUPJSONVALUE].append((_value, _key, normalizedValueKeyDict[_value]))
879
- else:
880
- normalizedValueKeyDict[_value] = _key
881
- if not NCNamePattern.match(_key):
882
- ldError("{}:invalidJSONStructure",
883
- _("The %(map)s alias \"%(alias)s\" must be a canonical NCName value"),
884
- modelObject=modelXbrl, map=key, alias=_key)
885
- if UrlInvalidPattern.match(_value):
886
- ldError("{}:invalidJSONStructure",
887
- _("The %(map)s alias \"%(alias)s\" URI must be a canonical URI value: \"%(URI)s\"."),
888
- modelObject=modelXbrl, map=key, alias=_key, URI=_value)
889
- elif not (_value and isAbsoluteUri(_value)) or UrlInvalidPattern.match(_value):
890
- ldError("oimce:invalidURI",
891
- _("The %(map)s \"%(alias)s\" URI is invalid: \"%(URI)s\"."),
892
- modelObject=modelXbrl, map=key, alias=_key, URI=_value)
893
- value.clear() # replace with normalized values
894
- for _key, _value in normalizedDict.items():
895
- value[_key] = _value
896
- if DUPJSONKEY in value:
897
- for _errKey, _errValue, _otherValue in value[DUPJSONKEY]:
898
- if key in ("namespaces", "linkTypes", "linkGroups"):
899
- ldError("{}:invalidJSON", # {} expanded when loadDictErrors are processed
900
- _("The %(map)s alias \"%(prefix)s\" is used on uri \"%(uri1)s\" and uri \"\"%(uri2)s."),
901
- modelObject=modelXbrl, map=key, prefix=_errKey, uri1=_errValue, uri2=_otherValue)
902
- else:
903
- ldError("{}:invalidJSON", # {} expanded when loadDictErrors are processed
904
- _("The %(obj)s key \"%(key)s\" is used on multiple objects."),
905
- modelObject=modelXbrl, obj=key, key=_errKey)
906
- del value[DUPJSONKEY]
907
- if DUPJSONVALUE in value:
908
- if key in ("namespaces", "linkTypes", "linkGroups"):
909
- for _errValue, _errKey, _otherKey in value[DUPJSONVALUE]:
910
- ldError("oimce:multipleAliasesForURI",
911
- _("The \"%(map)s\" value \"%(uri)s\" is used on alias \"%(alias1)s\" and alias \"%(alias2)s\"."),
912
- modelObject=modelXbrl, map=key, uri=_errValue, alias1=_errKey, alias2=_otherKey)
913
- del value[DUPJSONVALUE]
914
- if key in _dict: # don't put the duplicate in the dictionary but report it as error
915
- if DUPJSONKEY not in _dict:
916
- _dict[DUPJSONKEY] = []
917
- _dict[DUPJSONKEY].append((key, value, _dict[key]))
918
- else: # do put into dictionary, only report if it's a map object
919
- _dict[key] = value
920
- if isinstance(value, str):
921
- if value in _valueKeyDict:
922
- if DUPJSONVALUE not in _dict:
923
- _dict[DUPJSONVALUE] = []
924
- _dict[DUPJSONVALUE].append((value, key, _valueKeyDict[value]))
925
- else:
926
- _valueKeyDict[value] = key
927
- return _dict
928
-
929
- primaryOimFile = oimFile
930
- extensionProperties = OrderedDict() # key is property QName, value is property path
931
-
932
- def loadOimObject(oimFile, extendingFile, visitedFiles, extensionChain, primaryReportParameters=None): # returns oimObject, oimWb
933
- # isXL means metadata loaded from Excel (but instance data can be in excel or CSV)
934
- isXL = oimFile.endswith(".xlsx") or oimFile.endswith(".xls")
935
- # same logic as modelDocument.load
936
- normalizedUrl = modelXbrl.modelManager.cntlr.webCache.normalizeUrl(oimFile, extendingFile)
937
- if modelXbrl.fileSource.isMappedUrl(normalizedUrl):
938
- mappedUrl = modelXbrl.fileSource.mappedUrl(normalizedUrl)
939
- elif PackageManager.isMappedUrl(normalizedUrl):
940
- mappedUrl = PackageManager.mappedUrl(normalizedUrl)
941
- else:
942
- mappedUrl = modelXbrl.modelManager.disclosureSystem.mappedUrl(normalizedUrl)
943
- if modelXbrl.fileSource.isInArchive(mappedUrl):
944
- filepath = mappedUrl
945
- else:
946
- filepath = modelXbrl.modelManager.cntlr.webCache.getfilename(mappedUrl) # , reload=reloadCache, checkModifiedTime=kwargs.get("checkModifiedTime",False))
947
- if filepath:
948
- url = modelXbrl.modelManager.cntlr.webCache.normalizeUrl(filepath)
949
- if filepath and filepath.endswith(".csv") or ("metadata" in filepath and filepath.endswith(".json")):
950
- errPrefix = "xbrlce"
951
- else:
952
- errPrefix = "xbrlje"
953
- # prevent recursion
954
- if filepath in extensionChain:
955
- raise OIMException("{}:cycleInExtensionChain".format(errPrefix),
956
- _("File MUST NOT extend itself: %(file)s cycles to %(extendingFile)s"),
957
- file=filepath, extendingFile=extendingFile)
958
- elif filepath in visitedFiles:
959
- return None
960
- visitedFiles.add(filepath)
961
- extensionChain.add(filepath)
962
- if not isXL:
963
- try:
964
- _file = modelXbrl.fileSource.file(filepath, encoding="utf-8-sig")[0]
965
- with _file as f:
966
- chars = f.read(16) # test encoding
967
- m = UTF_7_16_Pattern.match(chars)
968
- if m:
969
- raise OIMException("{}:invalidJSON".format(errPrefix),
970
- _("File MUST use utf-8 encoding: %(file)s, appears to be %(encoding)s"),
971
- file=filepath, encoding=m.lastgroup)
972
- else:
973
- f.seek(0)
974
- oimObject = json.load(f, object_pairs_hook=loadDict)
975
- except UnicodeDecodeError as ex:
976
- raise OIMException("{}:invalidJSON".format(errPrefix),
977
- _("File MUST use utf-8 encoding: %(file)s, error %(error)s"),
978
- file=filepath, error=str(ex))
979
- except json.JSONDecodeError as ex:
980
- raise OIMException("{}:invalidJSON".format(errPrefix),
981
- "JSON error while %(action)s, %(file)s, error %(error)s",
982
- file=filepath, action=currentAction, error=ex)
983
- # check for top-level key duplicates
984
- if isinstance(oimObject, dict) and DUPJSONKEY in oimObject:
985
- for _errKey, _errValue, _otherValue in oimObject[DUPJSONKEY]:
986
- error("{}:invalidJSON".format(errPrefix),
987
- _("The key %(key)s is used on multiple objects"),
988
- modelObject=modelXbrl, key=_errKey)
989
- del oimObject[DUPJSONKEY]
990
- oimWb = None
991
- elif isXL:
992
- _file = modelXbrl.fileSource.file(filepath, binary=True)[0]
993
- with _file as f:
994
- oimWb = load_workbook(f, data_only=True)
995
- if "metadata" not in oimWb:
996
- raise OIMException("xbrlwe:missingWorkbookWorksheets",
997
- _("Unable to identify worksheet tabs for metadata"))
998
- _foundMatch = False
999
- for row in range(1,10): # allow metadata to be indented or surrounded by column and row title columns
1000
- for col in range(1,10):
1001
- _metadata = xlValue(oimWb["metadata"].cell(row=row,column=col))
1002
- if _metadata and JSONmetadataPattern.match(_metadata): # find JSON metadata cell
1003
- _foundMatch = True
1004
- break
1005
- if _foundMatch:
1006
- break
1007
- try:
1008
- oimObject = json.loads(_metadata, object_pairs_hook=loadDict)
1009
- except UnicodeDecodeError as ex:
1010
- raise OIMException("{}:invalidJSON".format(errPrefix),
1011
- _("File MUST use utf-8 encoding: %(file)s \"metadata\" worksheet, error %(error)s"),
1012
- file=filepath, error=str(ex))
1013
- except json.JSONDecodeError as ex:
1014
- raise OIMException("{}:invalidJSON".format(errPrefix),
1015
- "JSON error while %(action)s, %(file)s \"metadata\" worksheet, error %(error)s",
1016
- file=filepath, action=currentAction, error=ex)
1017
- # allow report setup or extension objects processing
1018
- for pluginXbrlMethod in pluginClassMethods("LoadFromOim.DocumentSetup"):
1019
- pluginXbrlMethod(modelXbrl, oimObject, oimFile)
1020
- # identify document type (JSON or CSV)
1021
- documentInfo = jsonGet(oimObject, "documentInfo", {})
1022
- documentType = jsonGet(documentInfo, "documentType")
1023
- documentBase = jsonGet(documentInfo, "baseURL")
1024
- if documentType in jsonDocumentTypes:
1025
- isCSV = False
1026
- isJSON = True
1027
- errPrefix = "xbrlje"
1028
- oimMemberTypes = JsonMemberTypes
1029
- oimRequiredMembers = JsonRequiredMembers
1030
- elif documentType in csvDocumentTypes:
1031
- isJSON = False
1032
- isCSV = not isXL
1033
- errPrefix = "xbrlce"
1034
- oimMemberTypes = CsvMemberTypes
1035
- oimRequiredMembers = CsvRequiredMembers
1036
- else: # if wrong type defer to type checking
1037
- isCSV = False
1038
- isJSON = False
1039
- #errPrefix was set earlier based on file name
1040
- oimMemberTypes = UnrecognizedDocMemberTypes
1041
- oimRequiredMembers = UnrecognizedDocRequiredMembers
1042
- isCSVorXL = isCSV or isXL
1043
-
1044
- # report loadDict errors
1045
- for msgCode, msgText, kwargs in loadDictErrors:
1046
- error(msgCode.format(errPrefix), msgText, href=filepath, **kwargs)
1047
- del loadDictErrors[:]
1048
-
1049
- invalidMemberTypes = []
1050
- invalidSQNames = []
1051
- missingRequiredMembers = []
1052
- unexpectedMembers = []
1053
- def showPathObj(parts, obj): # this can be replaced with jsonPath syntax if appropriate
1054
- try:
1055
- shortObjStr = json.dumps(obj)
1056
- except TypeError:
1057
- shortObjStr = str(obj)
1058
- if len(shortObjStr) > 34:
1059
- shortObjStr = "{:.32}...".format(shortObjStr)
1060
- return "/{}={}".format("/".join(str(p) for p in parts), shortObjStr)
1061
- def checkMemberTypes(obj, path, pathParts):
1062
- if (isinstance(obj,dict)):
1063
- for missingMbr in oimRequiredMembers.get(path,EMPTY_SET) - obj.keys():
1064
- missingRequiredMembers.append(path + missingMbr)
1065
- for mbrName, mbrObj in obj.items():
1066
- mbrPath = path + mbrName
1067
- pathParts.append(mbrName)
1068
- # print("mbrName {} mbrObj {}".format(mbrName, mbrObj))
1069
- if mbrPath in oimMemberTypes:
1070
- mbrTypes = oimMemberTypes[mbrPath]
1071
- if (mbrTypes is SQNameType or (isinstance(mbrTypes,tuple) and SQNameType in mbrTypes)):
1072
- if not isinstance(mbrObj, str) or not SQNamePattern.match(mbrObj):
1073
- invalidSQNames.append(showPathObj(pathParts, mbrObj))
1074
- elif (not ((mbrTypes is QNameType or (isinstance(mbrTypes,tuple) and QNameType in mbrTypes)) and isinstance(mbrObj, str) and QNamePattern.match(mbrObj)) and
1075
- not ((mbrTypes is LangType or (isinstance(mbrTypes,tuple) and LangType in mbrTypes)) and isinstance(mbrObj, str) and languagePattern.match(mbrObj)) and
1076
- not ((mbrTypes is URIType or (isinstance(mbrTypes,tuple) and URIType in mbrTypes)) and isinstance(mbrObj, str) and isValidUriReference(mbrObj) and not WhitespaceUntrimmedPattern.match(mbrObj)) and
1077
- #not (mbrTypes is IdentifierType and isinstance(mbrObj, str) and isinstance(mbrObj, str) and IdentifierPattern.match(mbrObj)) and
1078
- not ((mbrTypes is int or (isinstance(mbrTypes,tuple) and int in mbrTypes)) and isinstance(mbrObj, str) and CanonicalIntegerPattern.match(mbrObj)) and
1079
- not isinstance(mbrObj, mbrTypes)):
1080
- invalidMemberTypes.append(showPathObj(pathParts, mbrObj))
1081
- elif ":" in mbrName and path + "*:*" in oimMemberTypes:
1082
- _mbrTypes = oimMemberTypes[path + "*:*"]
1083
- if not (QNamePattern.match(mbrName) and isinstance(mbrObj, _mbrTypes)):
1084
- invalidMemberTypes.append(showPathObj(pathParts, mbrObj))
1085
- elif isinstance(_mbrTypes,tuple):
1086
- if CheckPrefix in _mbrTypes:
1087
- extensionProperties[mbrName] = showPathObj(pathParts, mbrObj)
1088
- if NoRecursionCheck in _mbrTypes:
1089
- continue # custom types, block recursive check
1090
- mbrPath = path + "*:*" # for recursion
1091
- elif path + "*" in oimMemberTypes:
1092
- mbrTypes = oimMemberTypes[path + "*"]
1093
- if (not ((mbrTypes is URIType or (isinstance(mbrTypes,tuple) and isinstance(mbrObj, str) and URIType in mbrTypes)) and isValidUriReference(mbrObj)) and
1094
- not isinstance(mbrObj, mbrTypes)):
1095
- invalidMemberTypes.append(showPathObj(pathParts, mbrObj))
1096
- if isinstance(mbrTypes,tuple) and KeyIsNcName in mbrTypes and not NCNamePattern.match(mbrName):
1097
- invalidMemberTypes.append(showPathObj(pathParts, mbrObj))
1098
- mbrPath = path + "*" # for recursion
1099
- else:
1100
- unexpectedMembers.append(showPathObj(pathParts, mbrObj))
1101
- if isinstance(mbrObj, (dict,list)):
1102
- checkMemberTypes(mbrObj, mbrPath + "/", pathParts)
1103
- pathParts.pop() # remove mbrName
1104
- if (isinstance(obj,list)):
1105
- mbrNdx = 1
1106
- for mbrObj in obj:
1107
- mbrPath = path # list entry just uses path ending in /
1108
- pathParts.append(mbrNdx)
1109
- if mbrPath in oimMemberTypes:
1110
- mbrTypes = oimMemberTypes[mbrPath]
1111
- if (not (mbrTypes is IdentifierType and isinstance(mbrObj, str) and isinstance(mbrObj, str) and IdentifierPattern.match(mbrObj)) and
1112
- not ((mbrTypes is URIType or (isinstance(mbrTypes,tuple) and URIType in mbrTypes)) and isinstance(mbrObj, str) and isValidUriReference(mbrObj) and not WhitespaceUntrimmedPattern.match(mbrObj)) and
1113
- not isinstance(mbrObj, mbrTypes)):
1114
- invalidMemberTypes.append(showPathObj(pathParts, mbrObj))
1115
- if isinstance(mbrObj, (dict,list)):
1116
- checkMemberTypes(mbrObj, mbrPath + "/", pathParts)
1117
- pathParts.pop() # remove mbrNdx
1118
- mbrNdx += 1
1119
- checkMemberTypes(oimObject, "/", [])
1120
- numErrorsBeforeJsonCheck = len(modelXbrl.errors)
1121
- if not isJSON and not isCSV and not isXL:
1122
- error("oimce:unsupportedDocumentType",
1123
- _("Unrecognized /documentInfo/docType: %(documentType)s"),
1124
- documentType=documentType)
1125
- extensionChain.discard(filepath)
1126
- return {}
1127
- if missingRequiredMembers or unexpectedMembers:
1128
- msg = []
1129
- if missingRequiredMembers:
1130
- msg.append(_("Required element(s) are missing from metadata: %(missing)s"))
1131
- if unexpectedMembers:
1132
- msg.append(_("Unexpected element(s) in metadata: %(unexpected)s"))
1133
- error("{}:invalidJSONStructure".format(errPrefix),
1134
- "\n ".join(msg), documentType=documentType,
1135
- sourceFileLine=oimFile, missing=", ".join(missingRequiredMembers), unexpected=", ".join(unexpectedMembers))
1136
- if invalidMemberTypes:
1137
- error("{}:invalidJSONStructure".format(errPrefix),
1138
- _("Invalid JSON structure member types in metadata: %(members)s"),
1139
- sourceFileLine=oimFile, members=", ".join(invalidMemberTypes))
1140
- if invalidSQNames:
1141
- error("oimce:invalidSQName".format(errPrefix),
1142
- _("Invalid SQNames in metadata: %(members)s"),
1143
- sourceFileLine=oimFile, members=", ".join(invalidMemberTypes))
1144
-
1145
- if isCSV and not primaryReportParameters:
1146
- primaryReportParameters = oimObject.setdefault("parameters", {})
1147
10
 
1148
- # read reportParameters if in a CSV file relative to parent metadata file
1149
- if isinstance(oimObject.get("parameterURL"), str):
1150
- parameterURL = oimObject["parameterURL"]
1151
- parameterFilePath = os.path.join(os.path.dirname(primaryOimFile), parameterURL)
1152
- if modelXbrl.fileSource.exists(parameterFilePath):
1153
- problems = []
1154
- badIdentifiers = []
1155
- identifiersInThisFile = set()
1156
- for i, row in enumerate(openCsvReader(parameterFilePath, CSV_PARAMETER_FILE)):
1157
- if i == 0:
1158
- if row != ["name", "value"]:
1159
- problems.append(_("The first row must only consist of \"name\" and \"value\" but contains: {}").format(",".join(row)))
1160
- elif len(row) > 0 and row[0]:
1161
- name = row[0]
1162
- if not IdentifierPattern.match(name):
1163
- badIdentifiers.append(_("Row {} column 1 is not a valid identifier: {}").format(i+1, name))
1164
- elif len(row) < 2 or not row[1]:
1165
- problems.append(_("Row {} value column 2 missing").format(i+1))
1166
- elif any(cell for cell in row[2:]):
1167
- problems.append(_("Row {} columns 3 - {} must be empty").format(i+1, len(row)))
1168
- # no longer illegal to override primary report parameters... but between csv files is it illegal?
1169
- #elif row[0] in primaryReportParameters:
1170
- # if primaryReportParameters[row[0]] != row[1]:
1171
- # error("xbrlce:illegalReportParameterRedefinition",
1172
- # _("Report parameter %(name)s redefined in file %(file)s, report value %(value1)s, csv value %(value2)s"),
1173
- # file=parameterURL, name=row[0], value1=primaryReportParameters[row[0]], value2=row[1])
1174
- elif name in identifiersInThisFile:
1175
- problems.append(_("Row {} column 1 is has a repeated identifier: {}").format(i+1, name))
1176
- else:
1177
- identifiersInThisFile.add(name)
1178
- primaryReportParameters[name] = row[1]
1179
- elif any(cell for cell in row):
1180
- problems.append(_("Row {} has no identifier, all columns must be empty").format(i+1))
1181
- if badIdentifiers:
1182
- error("xbrlce:invalidIdentifier",
1183
- _("Report parameter file %(file)s:\n %(issues)s"),
1184
- file=parameterURL, issues=", \n".join(badIdentifiers))
1185
- if problems:
1186
- error("xbrlce:invalidParameterCSVFile",
1187
- _("Report parameter file %(file)s issues:\n %(issues)s"),
1188
- file=parameterURL, issues=", \n".join(problems))
1189
- else:
1190
- error("xbrlce:missingParametersFile",
1191
- _("Report parameter file is missing: %(file)s"),
1192
- file=parameterURL)
1193
11
 
1194
- if isCSVorXL: # normalize relative taxonomy URLs to primary document or nearest absolute parent
1195
- t = documentInfo.get("taxonomy",())
1196
- for i, tUrl in enumerate(t):
1197
- t[i] = modelXbrl.modelManager.cntlr.webCache.normalizeUrl(tUrl, normalizedUrl)
1198
-
1199
- if isCSVorXL and "extends" in documentInfo:
1200
- # process extension
1201
- for extendedFile in documentInfo["extends"]:
1202
- try:
1203
- extendedOimObject = loadOimObject(extendedFile, mappedUrl, visitedFiles, extensionChain)
1204
- except IOError:
1205
- error("{}:unresolvableBaseMetadataFile".format(errPrefix),
1206
- _("Extending document file not found: %(extendingFile)s, referenced from %(extendedFile)s"),
1207
- extendingFile=extendedFile, extendedFile=oimFile)
1208
- raise OIMException()
1209
- if extendedOimObject is None:
1210
- continue # None returned when directed cycle blocks reloading same file
1211
- # extended must be CSV
1212
- extendedDocumentInfo = extendedOimObject.get("documentInfo", EMPTY_DICT)
1213
- extendedDocumentType = extendedDocumentInfo.get("documentType")
1214
- extendedFinal = extendedDocumentInfo.get("final", EMPTY_DICT)
1215
- if extendedDocumentType != documentType:
1216
- error("{}:multipleDocumentTypesInExtensionChain".format(errPrefix),
1217
- _("Extended documentType %(extendedDocumentType)s must same as extending documentType %(documentType)s in file %(extendedFile)s"),
1218
- extendedFile=extendedFile, extendedDocumentType=extendedDocumentType, documentType=documentType)
1219
- raise OIMException()
1220
- oimParameters = oimObject.setdefault("parameters", {})
1221
- for paramName, paramValue in extendedOimObject.get("parameters",{}).items():
1222
- if paramName in oimParameters and oimParameters[paramName] != paramValue:
1223
- error("xbrlce:illegalReportParameterRedefinition",
1224
- _("Report parameter %(name)s redefined in file %(file)s, extended value %(value1)s, extending value %(value2)s"),
1225
- file=extendedFile, name=paramName, value1=oimParameters[paramName], value2=paramValue)
1226
- else:
1227
- oimParameters[paramName] = paramValue
1228
- for parent, extendedParent, excludedObjectNames in (
1229
- (documentInfo, extendedDocumentInfo, {"documentType", "extends"}),
1230
- (oimObject, extendedOimObject, {"documentInfo"})):
1231
- for objectName in extendedFinal:
1232
- if objectName not in excludedObjectNames and objectName not in extendedParent and objectName in parent:
1233
- error("xbrlce:illegalExtensionOfFinalProperty",
1234
- _("Extended file %(extendedFile)s redefines final object %(finalObjectName)s"),
1235
- extendedFile=extendedFile, finalObjectName=objectName)
1236
- for objectName in extendedParent.keys() - excludedObjectNames:
1237
- if objectName in csvExtensibleObjects:
1238
- for parProp, parPropValue in parent.get(objectName,EMPTY_DICT).items():
1239
- if extendedFinal.get(objectName, False) and parProp not in extendedParent.get(objectName,EMPTY_DICT):
1240
- error("xbrlce:illegalExtensionOfFinalProperty",
1241
- _("Extended file %(extendedFile)s specifies final object %(objectName)s property %(property)s"),
1242
- extendedFile=oimFile, objectName=objectName, property=parProp)
1243
- for extProp, extPropValue in extendedParent.get(objectName,EMPTY_DICT).items():
1244
- if extProp in parent.get(objectName,EMPTY_DICT):
1245
- if json.dumps(extPropValue,sort_keys=True) != json.dumps(parent[objectName][extProp],sort_keys=True): # ordered dicts, especially nested are not comparable
1246
- error("xbrlce:conflictingMetadataValue" if extendedFinal.get(objectName, False)
1247
- else "xbrlce:conflictingMetadataValue",
1248
- _("Extended file %(extendedFile)s redefines object %(objectName)s property %(property)s"),
1249
- extendedFile=extendedFile, objectName=objectName, property=extProp)
1250
- else:
1251
- if objectName not in parent:
1252
- parent[objectName] = {}
1253
- parent[objectName][extProp] = extPropValue
1254
- elif objectName in parent:
1255
- if objectName == "taxonomy":
1256
- for extPropValue in extendedParent["taxonomy"]:
1257
- if extPropValue not in parent["taxonomy"]:
1258
- parent["taxonomy"].append(extPropValue)
1259
- elif extendedParent[objectName] != parent[objectName]:
1260
- error("xbrlce:illegalRedefinitionOfNonExtensibleProperty",
1261
- _("Extended file %(extendedFile)s redefines object %(objectName)s"),
1262
- extendedFile=extendedFile, objectName=objectName)
1263
- else:
1264
- parent[objectName] = extendedParent[objectName]
1265
-
1266
- if extendingFile is None: # entry oimFile
1267
- if ("taxonomy" in documentInfo or isCSV) and not documentInfo.get("taxonomy",()):
1268
- error("oime:noTaxonomy",
1269
- _("The list of taxonomies MUST NOT be empty."))
1270
- if len(modelXbrl.errors) > numErrorsBeforeJsonCheck:
1271
- raise OIMException()
1272
-
1273
- oimObject["=entryParameters"] = (isJSON, isCSV, isXL, isCSVorXL, oimWb, documentInfo, documentType, documentBase)
1274
-
1275
- extensionChain.discard(filepath)
1276
- return oimObject
1277
-
1278
- errorIndexBeforeLoadOim = len(modelXbrl.errors)
1279
- oimObject = loadOimObject(oimFile, None, set(), set())
1280
- try:
1281
- isJSON, isCSV, isXL, isCSVorXL, oimWb, oimDocumentInfo, documentType, documentBase = oimObject["=entryParameters"]
1282
- except KeyError:
1283
- raise OIMException() # no document
1284
- del oimObject["=entryParameters"]
1285
-
1286
- currentAction = "identifying Metadata objects"
1287
- taxonomyRefs = oimDocumentInfo.get("taxonomy", EMPTY_LIST)
1288
- namespaces = oimDocumentInfo.get("namespaces", EMPTY_DICT)
1289
- linkTypes = oimDocumentInfo.get("linkTypes", EMPTY_DICT)
1290
- linkGroups = oimDocumentInfo.get("linkGroups", EMPTY_DICT)
1291
- featuresDict = oimDocumentInfo.get("features", EMPTY_DICT)
1292
- documentInfoProperties = {"documentType", "features", "namespaces", "linkTypes", "linkGroups", "taxonomy", "baseURL"}
1293
- oimObjectProperties = {}
1294
- factProperties = {"decimals", "dimensions", "links", "value"}
1295
- canonicalValuesFeature = False
1296
- if isJSON:
1297
- errPrefix = "xbrlje"
1298
- valErrPrefix = "xbrlje"
1299
- OIMReservedAliasURIs["namespaces"] = NSReservedAliasURIs.copy()
1300
- OIMReservedAliasURIs["namespaces"].update(JSONNSReservedAliasURIs)
1301
- OIMReservedURIAlias["namespaces"] = NSReservedURIAlias.copy()
1302
- OIMReservedURIAlias["namespaces"].update(JSONNSReservedURIAliases)
1303
- factItems = oimObject.get("facts",{}).items()
1304
- footnotes = oimObject.get("facts",{}).values() # shares this object
1305
- canonicalValuesFeature = featuresDict.get("xbrl:canonicalValues") in (True, "true")
1306
- else: # isCSVorXL
1307
- errPrefix = "xbrlce"
1308
- valErrPrefix = "xbrlce"
1309
- OIMReservedAliasURIs["namespaces"] = NSReservedAliasURIs.copy()
1310
- OIMReservedAliasURIs["namespaces"].update(CSVNSReservedAliasURIs)
1311
- OIMReservedURIAlias["namespaces"] = NSReservedURIAlias.copy()
1312
- OIMReservedURIAlias["namespaces"].update(CSVNSReservedURIAliases)
1313
- reportDimensions = oimObject.get("dimensions", EMPTY_DICT)
1314
- reportDecimals = oimObject.get("decimals", None)
1315
- reportParameters = oimObject.get("parameters", {}) # fresh empty dict because csv-loaded parameters get added
1316
- tableTemplates = oimObject.get("tableTemplates", EMPTY_DICT)
1317
- tables = oimObject.get("tables", EMPTY_DICT)
1318
- footnotes = (oimObject.get("links", {}), )
1319
- final = oimObject.get("final", EMPTY_DICT)
1320
- documentInfoProperties.add("extends")
1321
- documentInfoProperties.add("final")
1322
- reportProperties = {"documentInfo", "tableTemplates", "tables", "parameters", "parameterURL", "dimensions", "decimals", "links"}
1323
- columnProperties = {"comment", "decimals", "dimensions", "propertyGroups", "parameterURL", "propertiesFrom"}
1324
-
1325
- entityNaQName = qname(re_sub("/xbrl-(json|csv)$","/entities",documentType), "NA")
1326
- allowedDuplicatesFeature = ALL
1327
- v = featuresDict.get("xbrl:allowedDuplicates")
1328
- if v is not None:
1329
- if v in AllowedDuplicatesFeatureValues:
1330
- allowedDuplicatesFeature = AllowedDuplicatesFeatureValues[v]
1331
- else:
1332
- error("{}:invalidJSONStructure".format(errPrefix),
1333
- _("The xbbrl:allowedDuplicates feature has an invalid value: %(value)s"),
1334
- value=v)
1335
-
1336
- # check extension properties (where metadata specifies CheckPrefix)
1337
- for extPropSQName, extPropertyPath in extensionProperties.items():
1338
- extPropPrefix = extPropSQName.partition(":")[0]
1339
- if extPropPrefix not in namespaces:
1340
- error("oimce:unboundPrefix",
1341
- _("The extension property QName prefix was not defined in namespaces: %(extensionProperty)s."),
1342
- modelObject=modelXbrl, extensionProperty=extPropertyPath)
1343
-
1344
- # check features
1345
- for featureSQName, isActive in featuresDict.items():
1346
- featurePrefix = featureSQName.partition(":")[0]
1347
- if featurePrefix not in namespaces:
1348
- error("oimce:unboundPrefix",
1349
- _("The feature QName prefix was not defined in namespaces: %(feature)s."),
1350
- modelObject=modelXbrl, feature=featureSQName)
1351
-
1352
- # check maps
1353
- for alias, uris in NSReservedAliasURIs.items():
1354
- for uri in uris:
1355
- NSReservedURIAlias[uri] = alias
1356
-
1357
- for map in ("namespaces", "linkTypes", "linkGroups"):
1358
- for key, value in oimDocumentInfo.get(map, EMPTY_DICT).items():
1359
- if key in OIMReservedAliasURIs[map] and value not in OIMReservedAliasURIs[map][key]:
1360
- error("oimce:invalidURIForReservedAlias",
1361
- _("The %(map)s URI \"%(uri)s\" is used on standard alias \"%(alias)s\" which requires URI \"%(standardUri)s\"."),
1362
- modelObject=modelXbrl, map=map, alias=key, uri=value, standardUri=OIMReservedAliasURIs[map][key][0])
1363
- elif value in OIMReservedURIAlias[map] and key != OIMReservedURIAlias[map][value]:
1364
- error("oimce:invalidAliasForReservedURI",
1365
- _("The %(map)s URI \"%(uri)s\" is bound to alias \"%(key)s\" instead of standard alias \"%(alias)s\"."),
1366
- modelObject=modelXbrl, map=key, key=key, uri=value, alias=OIMReservedURIAlias[map][value])
1367
-
1368
- # check baseURL
1369
- if documentBase and not isAbsoluteUri(documentBase):
1370
- error("oime:invalidBaseURL",
1371
- _("The base-url must be absolute: \"%(url)s\"."),
1372
- modelObject=modelXbrl, url=documentBase)
1373
-
1374
- factProduced = FactProduced() # pass back fact info to csv Fact producer
1375
-
1376
- if isCSVorXL:
1377
- currentAction = "loading CSV facts tables"
1378
- _dir = os.path.dirname(oimFile)
1379
-
1380
- def csvFacts():
1381
- parseMetadataCellValues(reportDimensions)
1382
- for tableId, table in tables.items():
1383
- _file = tablePath = None
1384
- try: # note that decoder errors may occur late during streaming of rows
1385
- tableTemplateId = table.get("template", tableId)
1386
- tableTemplate = tableTemplates[tableTemplateId]
1387
- # tableIsTransposed = tableTemplate.get("transposed", False)
1388
- tableDecimals = tableTemplate.get("decimals")
1389
- tableDimensions = tableTemplate.get("dimensions", EMPTY_DICT)
1390
- parseMetadataCellValues(tableDimensions)
1391
- tableIsOptional = table.get("optional", False)
1392
- tableParameters = table.get("parameters", EMPTY_DICT)
1393
- rowIdColName = tableTemplate.get("rowIdColumn")
1394
- tableUrl = table["url"]
1395
- tableParameterColNames = set()
1396
- hasHeaderError = False # set to true blocks handling file beyond header row
1397
-
1398
- # compile column dependencies
1399
- factDimensions = {} # keys are column, values are dimensions object
1400
- factDecimals = {} # keys are column
1401
- propertyGroups = {}
1402
- propertiesFrom = {}
1403
- dimensionsColumns = set()
1404
- commentColumns = set()
1405
- extensionColumnProperties = defaultdict(dict)
1406
- for colId, colProperties in tableTemplate["columns"].items():
1407
- isCommentColumn = colProperties.get("comment") == True
1408
- if isCommentColumn:
1409
- commentColumns.add(colId)
1410
- else:
1411
- factDimensions[colId] = colProperties.get("dimensions")
1412
- factDecimals[colId] = colProperties.get("decimals")
1413
- isFactColumn = "dimensions" in colProperties
1414
- if "propertiesFrom" in colProperties:
1415
- isFactColumn = True
1416
- propertiesFrom[colId] = colProperties["propertiesFrom"]
1417
- if not isFactColumn and not isCommentColumn:
1418
- dimensionsColumns.add(colId) # neither comment nor fact column
1419
- isPropertyGroupColumn = "propertyGroups" in colProperties
1420
- if isPropertyGroupColumn:
1421
- propertyGroups[colId] = colProperties["propertyGroups"]
1422
- for extPropSQName, prop in colProperties.items():
1423
- if extPropSQName not in columnProperties:
1424
- extensionColumnProperties[colId][extPropSQName] = prop
1425
- # check table parameters
1426
- tableParameterReferenceNames = set()
1427
- def checkParamRef(paramValue, factColName=None, dimName=None):
1428
- if isinstance(paramValue, str) and paramValue.startswith("$") and not paramValue.startswith("$$"):
1429
- paramName = paramValue[1:].partition("@")[0]
1430
- tableParameterReferenceNames.add(paramName)
1431
- unitDims = set()
1432
- for factColName, colDims in factDimensions.items():
1433
- if colDims is not None:
1434
- factDims = set()
1435
- for inheritedDims in (colDims, tableDimensions, reportDimensions):
1436
- for dimName, dimValue in inheritedDims.items():
1437
- checkParamRef(dimValue, factColName, dimName)
1438
- factDims.add(dimName)
1439
- parseMetadataCellValues(colDims)
1440
- for _factDecimals in (factDecimals.get(factColName), tableDecimals, reportDecimals):
1441
- if "decimals" not in factDims:
1442
- checkParamRef(_factDecimals, factColName, "decimals")
1443
-
1444
- if hasHeaderError:
1445
- return
1446
- # determine whether table is a CSV file or an Excel range.
1447
- # Local range can be sheetname! or !rangename
1448
- # url to workbook with range must be url#sheet! or url#!range or url!range (unencoded !)
1449
- tableWb = None
1450
- _file = None
1451
- _rowIterator = None
1452
- _cellValue = None
1453
- if isXL and not ("#" in tableUrl or ".xlsx" in tableUrl or ".csv" in tableUrl):
1454
- # local Workbook range
1455
- tableWb = oimWb
1456
- _cellValue = xlValue
1457
- xlSheetName, _sep, xlNamedRange = tableUrl.partition('!')
1458
- else:
1459
- # check if there's a reference to an Excel workbook file
1460
- if "#" in tableUrl:
1461
- tableUrl, _sep, sheetAndRange = tableUrl.partition("#")
1462
- xlSheetName, _sep, xlNamedRange = sheetAndRange.partition('!')
1463
- tablePath = os.path.join(_dir, tableUrl)
1464
- # Remove unnecessary relative segments within path. Effected paths are handled fine
1465
- # when loading from directories, but this fails when loading from ZIP archives.
1466
- # OIM conformance suites expect this to be supported:
1467
- # oim-conf-2021-10-13.zip/300-csv-conformant-processor/V-11,
1468
- # "/300-csv-conformant-processor/./helloWorld-value-date-table2-facts.csv"
1469
- # oim-conf-2021-10-13.zip/300-csv-conformant-processor/V-12
1470
- # "/300-csv-conformant-processor/./helloWorld-SQNameSpecial-facts.csv"
1471
- tablePath = os.path.normpath(tablePath)
1472
- if not modelXbrl.fileSource.exists(tablePath):
1473
- if not tableIsOptional:
1474
- error("xbrlce:missingRequiredCSVFile",
1475
- _("Table %(table)s missing, url: %(url)s"),
1476
- table=tableId, url=tableUrl)
1477
- continue
1478
- if tableUrl.endswith(".xlsx"):
1479
- _file = modelXbrl.fileSource.file(tablePath, binary=True)[0]
1480
- tableWb = load_workbook(_file, data_only=True)
1481
- _cellValue = xlValue
1482
- else:
1483
- # must be CSV
1484
- _rowIterator = openCsvReader(tablePath, CSV_FACTS_FILE)
1485
- _cellValue = csvCellValue
1486
- # if tableIsTransposed:
1487
- # _rowIterator = transposer(_rowIterator)
1488
- if tableWb is not None:
1489
- hasSheetname = xlSheetName and xlSheetName in tableWb
1490
- hasNamedRange = xlNamedRange and xlNamedRange in tableWb.defined_names
1491
- if xlSheetName and not hasSheetname:
1492
- if tableIsOptional:
1493
- continue
1494
- raise OIMException("xbrlwe:missingTable",
1495
- _("Referenced table tab(s): %(missing)s"),
1496
- missing=tableUrl)
1497
- if xlNamedRange and not hasNamedRange:
1498
- if tableIsOptional:
1499
- continue
1500
- raise OIMException("xbrlwe:missingTableNamedRange",
1501
- _("Referenced named ranges tab(s): %(missing)s"),
1502
- missing=tableRangeName)
1503
- if hasNamedRange: # check type of range
1504
- defn = tableWb.defined_names[xlNamedRange]
1505
- if defn.type != "RANGE":
1506
- raise OIMException("xbrlwe:unusableRange",
1507
- _("Referenced range does not refer to a range: %(tableRange)s"),
1508
- tableRange=tableRangeName)
1509
- _rowIterator = []
1510
- if hasNamedRange:
1511
- for _tableName, _xlCellsRange in tableWb.defined_names[xlNamedRange].destinations:
1512
- rows = tableWb[_tableName][_xlCellsRange]
1513
- if isinstance(rows, Cell):
1514
- _rowIterator.append((rows, ))
1515
- else:
1516
- _rowIterator.extend(rows)
1517
- else: # use whole table
1518
- _rowIterator = tableWb[xlSheetName]
1519
- # if tableIsTransposed:
1520
- # _rowIterator = transposer(_rowIterator)
1521
-
1522
- rowIds = set()
1523
- paramRefColNames = set()
1524
- potentialInvalidReferenceTargets = {} # dimName: referenceTarget
1525
- for rowIndex, row in enumerate(_rowIterator):
1526
- if rowIndex == 0:
1527
- header = [_cellValue(cell) for cell in row]
1528
- emptyHeaderCols = set()
1529
- if isXL: # trim empty cells
1530
- header = xlTrimHeaderRow(header)
1531
- colNameIndex = dict((name, colIndex) for colIndex, name in enumerate(header))
1532
- idColIndex = colNameIndex.get(rowIdColName)
1533
- for colIndex, colName in enumerate(header):
1534
- if colName == "":
1535
- emptyHeaderCols.add(colIndex)
1536
- elif not IdentifierPattern.match(colName):
1537
- hasHeaderError = True
1538
- error("xbrlce:invalidHeaderValue",
1539
- _("Table %(table)s CSV file header column %(column)s is not a valid identifier: %(identifier)s, url: %(url)s"),
1540
- table=tableId, column=colIndex+1, identifier=colName, url=tableUrl)
1541
- elif colName not in factDimensions and colName not in commentColumns:
1542
- hasHeaderError = True
1543
- error("xbrlce:unknownColumn",
1544
- _("Table %(table)s CSV file header column %(column)s is not in table template definition: %(identifier)s, url: %(url)s"),
1545
- table=tableId, column=colIndex+1, identifier=colName, url=tableUrl)
1546
- elif colNameIndex[colName] != colIndex:
1547
- error("xbrlce:repeatedColumnIdentifier",
1548
- _("Table %(table)s CSV file header columns %(column)s and %(column2)s repeat identifier: %(identifier)s, url: %(url)s"),
1549
- table=tableId, column=colIndex+1, column2=colNameIndex[colName]+1, identifier=colName, url=tableUrl)
1550
- if colName in tableParameterReferenceNames and colName not in commentColumns:
1551
- paramRefColNames.add(colName)
1552
- #missingPropFromCols = flattenToSet(propertiesFrom.values()) - colNameIndex.keys()
1553
- #if missingPropFromCols:
1554
- # raise OIMException("xbrlce:invalidPropertyGroupColumnReference",
1555
- # _("Table %(table)s propertyFrom %(propFromColumns)s column missing, url: %(url)s"),
1556
- # table=tableId, propFromColumns=", ".join(sorted(missingPropFromCols)), url=tableUrl)
1557
- # check parameter references
1558
- checkedDims = set()
1559
- checkedParams = set()
1560
- def dimChecks():
1561
- for colName, colDims in factDimensions.items():
1562
- if colDims:
1563
- yield colDims, "column {} dimension".format(colName)
1564
- # no way to check parameterGroup dimensions at header-row processing time
1565
- for dims, source in ((tableDimensions, "table dimension"),
1566
- (reportDimensions, "report dimension"),
1567
- ):
1568
- yield dims, source
1569
- for colName, dec in factDecimals.items():
1570
- yield {"decimals": dec}, "column {} decimals".format(colName)
1571
- for dec, source in ((tableDecimals, "table decimals"),
1572
- (reportDecimals, "report decimals")):
1573
- if source:
1574
- yield {"decimals": dec}, source
1575
- for inheritedDims, dimSource in dimChecks():
1576
- for dimName, dimValue in inheritedDims.items():
1577
- if dimName not in checkedDims:
1578
- dimValue = inheritedDims[dimName]
1579
- # resolve column-relative dimensions
1580
- if isinstance(dimValue, str):
1581
- if dimValue.startswith("$"):
1582
- dimValue = dimValue[1:]
1583
- if not dimValue.startswith("$"):
1584
- dimValue, _sep, dimAttr = dimValue.partition("@")
1585
- if _sep and dimAttr not in ("start", "end"):
1586
- hasHeaderError = True
1587
- error("xbrlce:invalidPeriodSpecifier",
1588
- _("Table %(table)s %(source)s %(dimension)s period-specifier invalid: %(target)s, url: %(url)s"),
1589
- table=tableId, source=dimSource, dimension=dimName, target=dimAttr, url=tableUrl)
1590
- if dimValue not in checkedParams:
1591
- checkedParams.add(dimValue)
1592
- if dimValue in ("rowNumber", ) or (dimValue in header and dimValue not in commentColumns) or dimValue in tableParameters or dimValue in reportParameters:
1593
- checkedDims.add(dimValue)
1594
- else:
1595
- potentialInvalidReferenceTargets[dimName] = dimValue
1596
- elif ":" in dimName and ":" in dimValue:
1597
- dimConcept = modelXbrl.qnameConcepts.get(qname(dimName, namespaces))
1598
- if dimConcept is not None and dimConcept.isExplicitDimension:
1599
- memConcept = modelXbrl.qnameConcepts.get(qname(dimValue, namespaces))
1600
- if memConcept is not None and modelXbrl.dimensionDefaultConcepts.get(dimConcept) == memConcept:
1601
- error("xbrlce:invalidDimensionValue",
1602
- _("Table %(table)s %(source)s %(dimension)s value must not be the default member %(member)s, url: %(url)s"),
1603
- table=tableId, source=dimSource, dimension=dimName, member=dimValue, url=tableUrl)
1604
- for commentCol in commentColumns:
1605
- colNameIndex.pop(commentCol,None) # remove comment columns from col name index
1606
- unreportedFactDimensionColumns = factDimensions.keys() - set(header)
1607
- reportedDimensionsColumns = dimensionsColumns & set(header)
1608
- if hasHeaderError:
1609
- break # stop processing table
1610
- else:
1611
- rowId = None
1612
- paramColsWithValue = set()
1613
- paramColsUsed = set()
1614
- emptyCols = set()
1615
- emptyHeaderColsWithValue = []
1616
- if isXL and all(cell.value in (None, "") for cell in row): # skip empty excel rows
1617
- continue
1618
- rowPropGroups = {} # colName, propGroupObject for property groups in this row
1619
- rowPropGroupsUsed = set() # colNames used by propertiesFrom of fact col producing a fact
1620
- hasRowError = False
1621
- rowPropGrpParamRefs = set()
1622
- for propGrpName, propGrpObjects in propertyGroups.items():
1623
- propGrpColIndex = colNameIndex.get(propGrpName, 999999999)
1624
- if propGrpColIndex < len(row):
1625
- propGrpColValue = _cellValue(row[propGrpColIndex])
1626
- if propGrpColValue is NONE_CELL:
1627
- error("xbrlce:illegalUseOfNone",
1628
- _("Table %(table)s row %(row)s column %(column)s must not have #none, from %(source)s, url: %(url)s"),
1629
- table=tableId, row=rowIndex+1, column=colName, url=tableUrl, source=dimSource)
1630
- hasRowError = True
1631
- elif propGrpColValue in propGrpObjects:
1632
- rowPropGroups[propGrpName] = propGrpObjects[propGrpColValue]
1633
- else:
1634
- error("xbrlce:unknownPropertyGroup",
1635
- _("Table %(table)s unknown property group row %(row)s column %(column)s group %(propertyGroup)s, url: %(url)s"),
1636
- table=tableId, row=rowIndex+1, column=rowIdColName, url=tableUrl, propertyGroup=propGrpName)
1637
- hasRowError = True
1638
- if hasRowError:
1639
- continue
1640
- for colIndex, colValue in enumerate(row):
1641
- if colIndex >= len(header):
1642
- if _cellValue(colValue) != EMPTY_CELL:
1643
- emptyHeaderColsWithValue.append(colIndex)
1644
- continue
1645
- cellPropGroup = {}
1646
- propGroupDimSource = {}
1647
- colName = header[colIndex]
1648
- if colName == "":
1649
- if _cellValue(colValue) != EMPTY_CELL:
1650
- emptyHeaderColsWithValue.append(colIndex)
1651
- continue
1652
- if colName in commentColumns:
1653
- continue
1654
- propFromColNames = propertiesFrom.get(colName,EMPTY_LIST)
1655
- for propFromColName in propFromColNames:
1656
- if propFromColName in rowPropGroups:
1657
- for prop, val in rowPropGroups[propFromColName].items():
1658
- if isinstance(val, dict):
1659
- _valDict = cellPropGroup.setdefault(prop, {})
1660
- for dim, _val in val.items():
1661
- _valDict[dim] = _val
1662
- propGroupDimSource[dim] = propFromColName
1663
- if _val.startswith("$") and not _val.startswith("$$"):
1664
- rowPropGrpParamRefs.add(_val.partition("@")[0][1:])
1665
- else:
1666
- cellPropGroup[prop] = val
1667
- propGroupDimSource[prop] = propFromColName
1668
- if factDimensions[colName] is None:
1669
- if colName in paramRefColNames:
1670
- value = _cellValue(row[colNameIndex[colName]])
1671
- if value:
1672
- paramColsWithValue.add(colName)
1673
- elif value is EMPTY_CELL or value is NONE_CELL:
1674
- emptyCols.add(colName)
1675
- if not cellPropGroup:
1676
- continue # not a fact column
1677
- for rowPropGrpParamRef in rowPropGrpParamRefs:
1678
- value = _cellValue(row[colNameIndex[rowPropGrpParamRef]])
1679
- if value is EMPTY_CELL or value is NONE_CELL:
1680
- emptyCols.add(rowPropGrpParamRef)
1681
- # assemble row and fact Ids
1682
- if idColIndex is not None and not rowId:
1683
- if idColIndex < len(row):
1684
- rowId = _cellValue(row[idColIndex])
1685
- if not rowId:
1686
- error("xbrlce:missingRowIdentifier",
1687
- _("Table %(table)s missing row %(row)s column %(column)s row identifier, url: %(url)s"),
1688
- table=tableId, row=rowIndex+1, column=rowIdColName, url=tableUrl)
1689
- elif not RowIdentifierPattern.match(rowId):
1690
- error("xbrlce:invalidRowIdentifier",
1691
- _("Table %(table)s row %(row)s column %(column)s is not valid as a row identifier: %(identifier)s, url: %(url)s"),
1692
- table=tableId, row=rowIndex+1, column=rowIdColName, identifier=rowId, url=tableUrl)
1693
- elif rowId in rowIds:
1694
- error("xbrlce:repeatedRowIdentifier",
1695
- _("Table %(table)s row %(row)s column %(column)s is a duplicate: %(identifier)s, url: %(url)s"),
1696
- table=tableId, row=rowIndex+1, column=rowIdColName, identifier=rowId, url=tableUrl)
1697
- else:
1698
- rowIds.add(rowId)
1699
- paramColsUsed.add(rowIdColName)
1700
- factId = "{}.r_{}.{}".format(tableId, rowId or rowIndex, colName) # pre-pend r_ to rowId col value or row number if no rowId col value
1701
- fact = {}
1702
- # if this is an id column
1703
- cellValue = _cellValue(colValue) # nil facts return None, #empty string is ""
1704
- if cellValue is EMPTY_CELL: # no fact produced
1705
- continue
1706
- if cellValue is NONE_CELL:
1707
- error("xbrlce:illegalUseOfNone",
1708
- _("Table %(table)s row %(row)s column %(column)s must not have #none, from %(source)s, url: %(url)s"),
1709
- table=tableId, row=rowIndex+1, column=colName, url=tableUrl, source=dimSource)
1710
- continue
1711
- if cellPropGroup:
1712
- for propFromColName in propFromColNames:
1713
- rowPropGroupsUsed.add(propFromColName)
1714
- if colName in extensionColumnProperties: # merge extension properties to fact
1715
- fact.update(extensionColumnProperties[colName])
1716
- fact["value"] = cellValue
1717
- fact["dimensions"] = colFactDims = {}
1718
- noValueDimNames = set()
1719
- factDimensionSourceCol = {} # track consumption of column value dynamically
1720
- factDimensionPropGrpCol = {}
1721
- for inheritedDims, dimSource in ((factDimensions[colName], "column dimension"),
1722
- (cellPropGroup.get("dimensions",EMPTY_DICT), "propertyGroup {}".format(propFromColNames)),
1723
- (tableDimensions, "table dimension"),
1724
- (reportDimensions, "report dimension")):
1725
- for dimName, dimValue in inheritedDims.items():
1726
- if dimName not in colFactDims and dimName not in noValueDimNames:
1727
- dimValue = inheritedDims[dimName]
1728
- dimAttr = None
1729
- # resolve column-relative dimensions
1730
- if isinstance(dimValue, str) and dimValue.startswith("$"):
1731
- dimValue = dimValue[1:]
1732
- if not dimValue.startswith("$"):
1733
- paramName, _sep, dimAttr = dimValue.partition("@")
1734
- if paramName == "rowNumber":
1735
- dimValue = str(rowIndex)
1736
- elif paramName in colNameIndex:
1737
- dimValue = _cellValue(row[colNameIndex[paramName]])
1738
- if dimValue is EMPTY_CELL or dimValue is NONE_CELL: # csv file empty cell or none
1739
- dimValue = NONE_CELL
1740
- else:
1741
- factDimensionSourceCol[dimName] = paramName
1742
- elif paramName in tableParameters:
1743
- dimValue = tableParameters[paramName]
1744
- elif paramName in reportParameters:
1745
- dimValue = reportParameters[paramName]
1746
- elif paramName in unreportedFactDimensionColumns:
1747
- dimValue = NONE_CELL
1748
- else:
1749
- dimValue = INVALID_REFERENCE_TARGET
1750
- # else if in parameters?
1751
- if dimName == "period" and dimValue is not INVALID_REFERENCE_TARGET:
1752
- _dimValue = csvPeriod(dimValue, dimAttr)
1753
- if _dimValue == "referenceTargetNotDuration":
1754
- error("xbrlce:referenceTargetNotDuration",
1755
- _("Table %(table)s row %(row)s column %(column)s has instant date with period reference \"%(date)s\", from %(source)s, url: %(url)s"),
1756
- table=tableId, row=rowIndex+1, column=colName, date=dimValue, url=tableUrl, source=dimSource)
1757
- dimValue = NONE_CELL
1758
- elif _dimValue is None: # bad format, raised value error
1759
- error("xbrlce:invalidPeriodRepresentation",
1760
- _("Table %(table)s row %(row)s column %(column)s has lexical syntax issue with date \"%(date)s\", from %(source)s, url: %(url)s"),
1761
- table=tableId, row=rowIndex+1, column=colName, date=dimValue, url=tableUrl, source=dimSource)
1762
- dimValue = NONE_CELL
1763
- else:
1764
- dimValue = _dimValue
1765
- if dimValue is NONE_CELL:
1766
- noValueDimNames.add(dimName)
1767
- else:
1768
- colFactDims[dimName] = dimValue
1769
- if dimSource.startswith("propertyGroup"):
1770
- factDimensionPropGrpCol[dimName] = propGroupDimSource[dimName]
1771
- if factDecimals.get(colName) is not None:
1772
- dimValue = factDecimals[colName]
1773
- dimSource = "column decimals"
1774
- elif "decimals" in cellPropGroup:
1775
- dimValue = cellPropGroup["decimals"]
1776
- dimSource = "propertyGroup " + propFromColName
1777
- factDimensionPropGrpCol["decimals"] = propGroupDimSource[dimName]
1778
- elif tableDecimals is not None:
1779
- dimValue = tableDecimals
1780
- dimSource = "table decimals"
1781
- elif reportDecimals is not None:
1782
- dimValue = reportDecimals
1783
- dimSource = "report decimals"
1784
- else:
1785
- dimValue = None
1786
- dimSource = "absent"
1787
- if dimValue is not None:
1788
- validCsvCell = False
1789
- if isinstance(dimValue, str) and dimValue.startswith("$"):
1790
- paramName = dimValue[1:].partition("@")[0]
1791
- if paramName in colNameIndex:
1792
- dimSource += " from CSV column " + paramName
1793
- dimValue = _cellValue(row[colNameIndex[paramName]])
1794
- validCsvCell = integerPattern.match(dimValue or "") is not None # is None if is_XL
1795
- if dimValue is not NONE_CELL and dimValue != "" and dimValue != "#none":
1796
- factDimensionSourceCol["decimals"] = paramName
1797
- elif paramName in tableParameters:
1798
- dimSource += " from table parameter " + paramName
1799
- dimValue = tableParameters[paramName]
1800
- if dimValue != "" and dimValue != "#none" and integerPattern.match(dimValue):
1801
- dimValue = int(dimValue)
1802
- elif paramName in reportParameters:
1803
- dimSource += " from report parameter " + paramName
1804
- dimValue = reportParameters[paramName]
1805
- if dimValue != "" and dimValue != "#none" and integerPattern.match(dimValue):
1806
- dimValue = int(dimValue)
1807
- else:
1808
- dimValue = INVALID_REFERENCE_TARGET
1809
- validCsvCell = True # must wait to see if it's used later
1810
- if dimValue is INVALID_REFERENCE_TARGET:
1811
- fact["decimals"] = dimValue # allow referencing if not overridden by decimals suffix
1812
- elif dimValue is not NONE_CELL and dimValue != "" and dimValue != "#none":
1813
- if isinstance(dimValue, int) or validCsvCell:
1814
- fact["decimals"] = dimValue
1815
- else:
1816
- error("xbrlce:invalidDecimalsValue",
1817
- _("Table %(table)s row %(row)s column %(column)s has invalid decimals \"%(decimals)s\", from %(source)s, url: %(url)s"),
1818
- table=tableId, row=rowIndex+1, column=colName, decimals=dimValue, url=tableUrl, source=dimSource)
1819
- yield (factId, fact)
1820
- if factProduced.invalidReferenceTarget:
1821
- error("xbrlce:invalidReferenceTarget",
1822
- _("Table %(table)s %(dimension)s target not in table columns, parameters or report parameters: %(target)s, url: %(url)s"),
1823
- table=tableId, dimension=factProduced.invalidReferenceTarget, target=potentialInvalidReferenceTargets.get(factProduced.invalidReferenceTarget), url=tableUrl)
1824
- break # stop processing table
1825
- for dimName, dimSource in factDimensionSourceCol.items():
1826
- if dimName in factProduced.dimensionsUsed:
1827
- paramColsUsed.add(dimSource)
1828
- for dimName in factProduced.dimensionsUsed:
1829
- if dimName in factDimensionPropGrpCol:
1830
- paramColsUsed.add(factDimensionPropGrpCol[dimName])
1831
-
1832
- unmappedParamCols = (paramColsWithValue | rowPropGrpParamRefs | reportedDimensionsColumns) - paramColsUsed - emptyCols
1833
- if unmappedParamCols:
1834
- error("xbrlce:unmappedCellValue",
1835
- _("Table %(table)s row %(row)s unmapped parameter columns %(columns)s, url: %(url)s"),
1836
- table=tableId, row=rowIndex+1, columns=", ".join(sorted(unmappedParamCols)), url=tableUrl)
1837
- unmappedPropGrps = rowPropGroups.keys() - rowPropGroupsUsed
1838
- if unmappedPropGrps:
1839
- error("xbrlce:unmappedCellValue",
1840
- _("Table %(table)s row %(row)s unmapped property group columns %(columns)s, url: %(url)s"),
1841
- table=tableId, row=rowIndex+1, columns=", ".join(sorted(unmappedPropGrps)), url=tableUrl)
1842
- if emptyHeaderColsWithValue:
1843
- error("xbrlce:unmappedCellValue",
1844
- _("Table %(table)s row %(row)s empty-header columns with unmapped values in columns %(columns)s, url: %(url)s"),
1845
- table=tableId, row=rowIndex+1, columns=", ".join(str(c) for c in emptyHeaderColsWithValue), url=tableUrl)
1846
-
1847
- except UnicodeDecodeError as ex:
1848
- raise OIMException("{}:invalidJSON".format(errPrefix),
1849
- _("File MUST use utf-8 encoding: %(file)s, error %(error)s"),
1850
- file=tablePath, error=str(ex))
1851
- tableWb = None # dereference
1852
- _rowIterator = None # dereference
1853
- if _file is not None:
1854
- _file.close()
1855
-
1856
- factItems = csvFacts()
1857
-
1858
- currentAction = "identifying default dimensions"
1859
- if modelXbrl is not None:
1860
- ValidateXbrlDimensions.loadDimensionDefaults(modelXbrl) # needs dimension defaults
1861
-
1862
- currentAction = "validating OIM"
1863
-
1864
- # create the instance document
1865
- currentAction = "creating instance document"
1866
- # relativize taxonomyRefs to base where feasible
1867
- txBase = os.path.dirname(documentBase or (modelXbrl.entryLoadingUrl if modelXbrl else ""))
1868
- for i, tUrl in enumerate(taxonomyRefs or ()):
1869
- if not isAbsoluteUri(tUrl) and os.path.isabs(tUrl) and not isAbsoluteUri(txBase) and os.path.isabs(txBase):
1870
- taxonomyRefs[i] = os.path.relpath(tUrl, txBase)
1871
- prevErrLen = len(modelXbrl.errors) # track any xbrl validation errors
1872
- if modelXbrl: # pull loader implementation
1873
- modelXbrl.blockDpmDBrecursion = True
1874
- modelXbrl.modelDocument = _return = createModelDocument(
1875
- modelXbrl,
1876
- Type.INSTANCE,
1877
- instanceFileName,
1878
- schemaRefs=taxonomyRefs,
1879
- isEntry=True,
1880
- initialComment="extracted from OIM {}".format(mappedUri),
1881
- documentEncoding="utf-8",
1882
- base=documentBase or modelXbrl.entryLoadingUrl)
1883
- modelXbrl.modelDocument.inDTS = True
1884
- else: # API implementation
1885
- modelXbrl = ModelXbrl.create(
1886
- cntlr.modelManager,
1887
- Type.INSTANCE,
1888
- instanceFileName,
1889
- schemaRefs=taxonomyRefs,
1890
- isEntry=True,
1891
- initialComment="extracted from OIM {}".format(mappedUri),
1892
- base=documentBase)
1893
- _return = modelXbrl.modelDocument
1894
- if len(modelXbrl.errors) > prevErrLen:
1895
- error("oime:invalidTaxonomy",
1896
- _("Unable to obtain a valid taxonomy from URLs provided"),
1897
- modelObject=modelXbrl)
1898
-
1899
- currentAction = "identifying default dimensions"
1900
- if modelXbrl is not None:
1901
- ValidateXbrlDimensions.loadDimensionDefaults(modelXbrl) # needs dimension defaults
1902
-
1903
- # validate statically defined templates
1904
- if isCSVorXL:
1905
- currentAction = "checking statically defined dimensions in CSV templates"
1906
- prevErrLen = len(modelXbrl.errors) # track any xbrl validation errors
1907
- reportParametersUsed = set()
1908
-
1909
- def checkIdentifier(identifier, *pathSegs):
1910
- if not IdentifierPattern.match(identifier):
1911
- error("xbrlce:invalidIdentifier",
1912
- _("Invalid identifier: %(identifier)s at %(path)s"),
1913
- sourceFileLine=oimFile, identifier=identifier, path="/".join(pathSegs))
1914
- return False
1915
- return True # identifier is ok
1916
-
1917
- def checkSQName(sqname, *pathSegs):
1918
- if not SQNamePattern.match(sqname):
1919
- error("oimce:invalidSQName",
1920
- _("Invalid SQName: %(sqname)s"),
1921
- sourceFileLine=oimFile, sqname=sqname, path="/".join(pathSegs))
1922
- return False
1923
- return True # SQName is ok
1924
-
1925
- def checkDim(tblTmpl, dimName, dimValue, *pathSegs):
1926
- if dimValue is not None:
1927
- if isinstance(dimValue,str) and dimValue.startswith("#") and not SpecialValuePattern.match(dimValue):
1928
- error("xbrlce:unknownSpecialValue",
1929
- _("Unknown special value: %(value)s at %(path)s"),
1930
- modelObject=modelXbrl, value=dimValue, path="/".join(pathSegs+(dimName,)))
1931
- elif dimValue == "#nil" and ":" not in dimName and dimName not in ("concept", "period", "value", "entity", "unit"):
1932
- error("xbrlce:invalidJSONStructure",
1933
- _("Invalid value: %(value)s at %(path)s"),
1934
- modelObject=modelXbrl, value=dimValue, path="/".join(pathSegs+(dimName,)))
1935
- elif isinstance(dimValue,str) and dimValue.startswith("$") and not dimValue.startswith("$$"):
1936
- paramName, _sep, periodSpecifier = dimValue[1:].partition("@")
1937
- if _sep and periodSpecifier not in ("start", "end"):
1938
- error("xbrlce:invalidPeriodSpecifier",
1939
- _("Parameter period-specifier invalid: %(periodSpecifier)s at %(path)s"),
1940
- periodSpecifier=periodSpecifier, path="/".join(pathSegs+(dimName,)))
1941
- if not IdentifierPattern.match(paramName):
1942
- error("xbrlce:invalidReference",
1943
- _("Parameter reference invalid: %(target)s at %(path)s"),
1944
- target=paramName, path="/".join(pathSegs+(dimName,)))
1945
- reportParametersUsed.add(paramName)
1946
- if tblTmpl:
1947
- tblTmpl.setdefault("_parametersUsed",set()).add(paramName)
1948
- elif not (isinstance(dimValue,str) and dimValue.startswith("$")):
1949
- if dimName == "concept":
1950
- if dimValue != "#none":
1951
- if not isinstance(dimValue,str) or ":" not in dimValue or not QNamePattern.match(dimValue): # allow #nil
1952
- error("xbrlce:invalidConceptQName",
1953
- _("Concept does not match lexical QName pattern: %(concept)s at %(path)s"),
1954
- modelObject=modelXbrl, concept=dimValue, path="/".join(pathSegs+(dimName,)))
1955
- else:
1956
- conceptQn = qname(dimValue, namespaces)
1957
- if conceptQn is None: # bad prefix
1958
- error("oimce:unboundPrefix",
1959
- _("The QName prefix could not be resolved with available namespaces: %(concept)s at %(path)s"),
1960
- modelObject=modelXbrl, concept=dimValue, path="/".join(pathSegs+(dimName,)))
1961
- elif conceptQn.localName != "note" or conceptQn.namespaceURI not in nsOims:
1962
- concept = modelXbrl.qnameConcepts.get(conceptQn)
1963
- if concept is None:
1964
- error("oime:unknownConcept",
1965
- _("The concept QName could not be resolved with available DTS: %(concept)s at %(path)s"),
1966
- modelObject=modelXbrl, concept=dimValue, path="/".join(pathSegs+(dimName,)))
1967
- elif concept.isItem and concept.isAbstract:
1968
- error("oime:valueForAbstractConcept",
1969
- _("Value provided for abstract concept by %(concept)s at %(path)s"),
1970
- modelObject=modelXbrl, concept=dimValue, path="/".join(pathSegs+(dimName,)))
1971
- elif ((concept.instanceOfType(UNSUPPORTED_DATA_TYPES) and not concept.instanceOfType(dtrSQNameNamesItemTypes))
1972
- or concept.isTuple):
1973
- error("oime:unsupportedConceptDataType",
1974
- _("Concept has unsupported data type, %(dataType)s: %(concept)s at %(path)s"),
1975
- modelObject=modelXbrl, concept=dimValue, dataType=concept.typeQname, path="/".join(pathSegs+(dimName,)))
1976
- elif dimName == "unit":
1977
- if dimValue == "xbrli:pure":
1978
- error("oime:illegalPureUnit",
1979
- _("Unit MUST NOT have single numerator measure xbrli:pure with no denominators: %(unit)s at %(path)s"),
1980
- modelObject=modelXbrl, unit=dimValue, path="/".join(pathSegs+(dimName,)))
1981
- elif dimValue != "#none" and not UnitPattern.match( PrefixedQName.sub(UnitPrefixedQNameSubstitutionChar, dimValue) ):
1982
- error("oimce:invalidUnitStringRepresentation",
1983
- _("Unit string representation is lexically invalid, %(unit)s at %(path)s"),
1984
- modelObject=modelXbrl, unit=dimValue, path="/".join(pathSegs+(dimName,)))
1985
- elif dimName == "entity":
1986
- if dimValue != "#none":
1987
- checkSQName(dimValue or "", *(pathSegs+(dimName,)) )
1988
- dimQname = qname(dimValue, namespaces)
1989
- if dimQname == entityNaQName:
1990
- error("oime:invalidUseOfReservedIdentifier",
1991
- _("The entity core dimension MUST NOT have a scheme of 'https://xbrl.org/.../entities' with an identifier of 'NA': %(entity)s at %(path)s"),
1992
- modelObject=modelXbrl, entity=dimQname, path="/".join(pathSegs+(dimName,)))
1993
- elif dimName == "period":
1994
- if dimValue != "#none" and not PeriodPattern.match(csvPeriod(dimValue) or ""):
1995
- error("xbrlce:invalidPeriodRepresentation",
1996
- _("The period has lexically invalid dateTime %(period)s at %(path)s"),
1997
- modelObject=modelXbrl, period=dimValue, path="/".join(pathSegs+(dimName,)))
1998
- elif dimName == "language":
1999
- if dimValue != "#none" and not languagePattern.match(dimValue or ""):
2000
- error("xbrlce:invalidLanguageCode",
2001
- _("The language is lexically invalid %(language)s at %(path)s"),
2002
- modelObject=modelXbrl, language=dimValue, path="/".join(pathSegs+(dimName,)))
2003
- elif dimName == "decimals":
2004
- if dimValue != "#none" and not isinstance(dimValue,int) and not integerPattern.match(str(dimValue) or ""):
2005
- error("xbrlce:invalidDecimalsValue",
2006
- _("Decimals is lexically invalid %(language)s at %(path)s"),
2007
- modelObject=modelXbrl, language=dimValue, path="/".join(pathSegs+(dimName,)))
2008
- elif dimName == "xbrl:noteId":
2009
- error("xbrlce:invalidJSONStructure",
2010
- _("NoteId dimension must not be explicitly defined at %(path)s"),
2011
- modelObject=modelXbrl, qname=dimName, path="/".join(pathSegs+(dimName,)))
2012
- elif dimName.startswith("xbrl:"):
2013
- error("xbrlce:invalidJSONStructure",
2014
- _("Taxonomy-defined dimension must not have xbrl prefix: %(qname)s at %(path)s"),
2015
- modelObject=modelXbrl, qname=dimName, path="/".join(pathSegs+(dimName,)))
2016
- elif ":" in dimName: # taxonomy defined dimension
2017
- dimQname = qname(dimName, namespaces)
2018
- dimConcept = modelXbrl.qnameConcepts.get(dimQname)
2019
- if dimConcept is None:
2020
- error("oime:unknownDimension",
2021
- _("Taxonomy-defined dimension QName not be resolved with available DTS: %(qname)s at %(path)s"),
2022
- modelObject=modelXbrl, qname=dimQname, path="/".join(pathSegs+(dimName,)))
2023
- elif dimConcept.isExplicitDimension:
2024
- mem = qname(dimValue, namespaces)
2025
- if mem is None:
2026
- error("{}:invalidDimensionValue".format(valErrPrefix),
2027
- _("Taxonomy-defined explicit dimension value is invalid: %(memberQName)s at %(path)s"),
2028
- modelObject=modelXbrl, memberQName=dimValue, path="/".join(pathSegs+(dimName,)))
2029
- elif dimConcept.isTypedDimension:
2030
- # a modelObject xml element is needed for all of the instance functions to manage the typed dim
2031
- _type = dimConcept.typedDomainElement.type
2032
- if (_type is not None and
2033
- _type.qname != qnXbrliDateItemType and
2034
- (_type.localName in ("complexType", "union", "list", "ENTITY", "ENTITIES", "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "NOTATION")
2035
- or _type.isDerivedFrom(dtrPrefixedContentTypes))):
2036
- error("oime:unsupportedDimensionDataType",
2037
- _("Taxonomy-defined typed dimension value is complex: %(memberQName)s at %(path)s"),
2038
- modelObject=modelXbrl, memberQName=dimValue, path="/".join(pathSegs+(dimName,)))
2039
- if pathSegs[-1] in ("/dimensions", "dimensions") and not DimensionsKeyPattern.match(dimName):
2040
- error("oimce:invalidSQName",
2041
- _("Invalid SQName: %(sqname)s"),
2042
- sourceFileLine=oimFile, sqname=dimName, path="/".join(pathSegs))
2043
-
2044
- # check reportParameterNames
2045
- for reportParameterName in reportParameters.keys():
2046
- checkIdentifier(reportParameterName, "/parameters")
2047
- for dimName, dimValue in reportDimensions.items():
2048
- checkDim(None, dimName, dimValue, "/dimensions")
2049
- checkDim(None, "decimals", reportDecimals, "/")
2050
-
2051
- # check table template statically defined dimensions, regardless of use
2052
- for tblTmplId, tblTmpl in tableTemplates.items():
2053
- checkIdentifier(tblTmplId, "/tableTemplates")
2054
- propertyGroupCols = set()
2055
- columns = tblTmpl.get("columns",EMPTY_DICT)
2056
- for columnId, column in columns.items():
2057
- checkIdentifier(columnId, "/tableTemplates", tblTmplId, "columns", columnId)
2058
- if "propertyGroups" in column:
2059
- propertyGroupCols.add(columnId)
2060
- isCommentColumn = column.get("comment") == True
2061
- isFactColumn = "dimensions" in column or "propertiesFrom" in column
2062
- isPropertyGroupColumn = "propertyGroups" in column
2063
- if (isPropertyGroupColumn and isFactColumn) or (isCommentColumn and (isPropertyGroupColumn or isFactColumn)):
2064
- error("xbrlce:conflictingColumnType",
2065
- _("Conflicting column type at %(path)s"),
2066
- path="/tableTemplates/{}/columns/{}".format(tblTmplId, columnId))
2067
- if not isFactColumn and "decimals" in column:
2068
- error("xbrlce:misplacedDecimalsOnNonFactColumn",
2069
- _("Column has decimals on a non-fact column at %(path)s"),
2070
- path="/tableTemplates/{}/columns/{}".format(tblTmplId, columnId))
2071
-
2072
- for dimName, dimValue in tblTmpl.get("dimensions",EMPTY_DICT).items():
2073
- checkDim(tblTmpl, dimName, dimValue, "/tableTemplates", tblTmplId, "dimensions")
2074
- checkDim(tblTmpl, "decimals", tblTmpl.get("decimals",None), "/tableTemplates", tblTmplId)
2075
- for columnId, column in columns.items():
2076
- for dimName, dimValue in column.get("dimensions",EMPTY_DICT).items():
2077
- checkDim(tblTmpl, dimName, dimValue, "/tableTemplates", tblTmplId, "columns", columnId, "dimensions")
2078
- checkDim(tblTmpl, "decimals", column.get("decimals",None), "/tableTemplates", tblTmplId, "columns", columnId)
2079
- for propGrpName, propGrp in column.get("propertyGroups",EMPTY_DICT).items():
2080
- checkIdentifier(propGrpName, "/tableTemplates", tblTmplId, "columns", columnId, "propertyGroups", propGrpName)
2081
- for dimName, dimValue in propGrp.get("dimensions",EMPTY_DICT).items():
2082
- checkDim(tblTmpl, dimName, dimValue, "/tableTemplates", tblTmplId, "columns", columnId, "propertyGroups", propGrpName, "dimensions")
2083
- checkDim(tblTmpl, "decimals", propGrp.get("decimals",None), "/tableTemplates", tblTmplId, "columns", columnId, "propertyGroups", propGrpName)
2084
- decPGs = set()
2085
- dimPGs = defaultdict(set)
2086
- for propertyFrom in column.get("propertiesFrom",()):
2087
- if propertyFrom not in propertyGroupCols:
2088
- error("xbrlce:invalidPropertyGroupColumnReference",
2089
- _("PropertiesFrom value is not a column in table: %(propertyFrom)s at %(path)s"),
2090
- modelObject=modelXbrl, propertyFrom=propertyFrom, path="/tableTemplates/{}/columns/{}/propertiesFrom".format(tblTmplId,columnId))
2091
- else:
2092
- for propGrp in columns[propertyFrom].get("propertyGroups",EMPTY_DICT).values():
2093
- if "decimals" in propGrp:
2094
- decPGs.add(propertyFrom)
2095
- for dim in propGrp.get("dimensions",EMPTY_DICT).keys():
2096
- dimPGs[dim].add(propertyFrom)
2097
- if len(decPGs) > 1:
2098
- error("xbrlce:repeatedPropertyGroupDecimalsProperty",
2099
- _("PropertiesFrom references repeat decimals property: %(propFroms)s at %(path)s."),
2100
- propFroms=", ".join(decPGs), path="/tableTemplates/{}/columns/{}/propertiesFrom".format(tblTmplId,columnId))
2101
- if any(len(dimCols) > 1 for dimCols in dimPGs.values()):
2102
- error("xbrlce:repeatedPropertyGroupDimension",
2103
- _("PropertiesFrom references repeat dimensions from: %(propFroms)s, dimension: %(dimensions)s at %(path)s."),
2104
- propFroms=", ".join(sorted(set(c for d,cs in dimPGs.items() if len(cs) > 1 for c in cs))),
2105
- dimensions=", ".join(sorted(d for d,cs in dimPGs.items() if len(cs) > 1)),
2106
- path="/tableTemplates/{}/columns/{}/propertiesFrom".format(tblTmplId,columnId))
2107
-
2108
-
2109
- rowIdColName = tblTmpl.get("rowIdColumn")
2110
- if rowIdColName:
2111
- if rowIdColName not in columns:
2112
- error("xbrlce:undefinedRowIdColumn",
2113
- _("RowIdColumn is not defined in columns: %(rowIdColumn)s at %(path)s"),
2114
- rowIdColumn=rowIdColName, path="/tableTemplates/{}".format(tblTmplId))
2115
- elif columns[rowIdColName].get("comment") == True:
2116
- error("xbrlce:invalidRowIdColumn",
2117
- _("RowIdColumn must not be a comment column: %(rowIdColumn)s at %(path)s"),
2118
- rowIdColumn=rowIdColName, path="/tableTemplates/{}".format(tblTmplId))
2119
-
2120
- # table static checks
2121
- for tableId, table in tables.items():
2122
- checkIdentifier(tableId, "/tables")
2123
- tblTmplId = table.get("template", tableId)
2124
- if checkIdentifier(tblTmplId, "/tables/{}/template".format(tableId)) and tblTmplId not in tableTemplates:
2125
- error("xbrlce:unknownTableTemplate",
2126
- _("Referenced template is missing: %(tableTemplateId)s at %(path)s"),
2127
- modelObject=modelXbrl, tableTemplateId=tblTmplId, path="/tables/{}/template".format(tableId))
2128
- tblTmpl = tableTemplates.get(tblTmplId)
2129
- for tblParamName in table.get("parameters", EMPTY_DICT):
2130
- if not IdentifierPattern.match(tblParamName):
2131
- error("xbrlce:invalidParameterName",
2132
- _("Parameter name is not a valid identifier: %(tableParameterName)s at path: %(path)s"),
2133
- tableParameterName=tblParamName, path="/tables/{}/parameters".format(tableId))
2134
- # check for table parameter usage by its template
2135
- if tblTmpl and tblParamName not in tblTmpl.get("_parametersUsed",EMPTY_SET):
2136
- error("xbrlce:unreferencedParameter",
2137
- _("Parameter name is not referenced: %(tableParameterName)s at path: %(path)s"),
2138
- tableParameterName=tblParamName, path="/tables/{}/parameters".format(tableId))
2139
-
2140
- unreferencedReportParams = reportParameters.keys() - reportParametersUsed
2141
- if unreferencedReportParams:
2142
- error("xbrlce:unreferencedParameter",
2143
- _("Report parameters not referenced: %(parameters)s"),
2144
- parameters=", ".join(sorted(unreferencedReportParams)))
2145
-
2146
-
2147
- if len(modelXbrl.errors) > prevErrLen:
2148
- return NotOIMException() # no point to going ahead.
2149
-
2150
- firstCntxUnitFactElt = None
2151
-
2152
- cntxTbl = {}
2153
- unitTbl = {}
2154
- xbrlNoteTbl = {} # fact ID: note fact
2155
- noteFactIDsNotReferenced = set()
2156
-
2157
- currentAction = "creating facts"
2158
- factNum = 0 # for synthetic fact number
2159
- if isJSON:
2160
- syntheticFactFormat = "_f{{:0{}}}".format(int(log10(len(factItems) or 1))) #want
2161
- else:
2162
- syntheticFactFormat = "_f{}" #want
2163
-
2164
- numFactCreationXbrlErrors = 0
2165
-
2166
- contextElement = getTaxonomyContextElement(modelXbrl)
2167
- for id, fact in factItems:
2168
- factProduced.clear()
2169
-
2170
- dimensions = fact.get("dimensions", EMPTY_DICT)
2171
- if "concept" not in dimensions:
2172
- error("oime:missingConceptDimension",
2173
- _("The concept core dimension MUST be present on fact: %(id)s."),
2174
- modelObject=modelXbrl, id=id)
2175
- continue
2176
- if not id:
2177
- id = syntheticFactFormat.format(factNum)
2178
- factNum += 1
2179
- conceptSQName = dimensions["concept"]
2180
- if conceptSQName is INVALID_REFERENCE_TARGET:
2181
- factProduced.invalidReferenceTarget = "concept"
2182
- continue
2183
- factProduced.dimensionsUsed.add("concept")
2184
- if isCSVorXL and (not isinstance(conceptSQName,str) or ":" not in conceptSQName or not QNamePattern.match(conceptSQName or "")): # allow #nil
2185
- error("xbrlce:invalidConceptQName",
2186
- _("Concept does not match lexical QName pattern: %(concept)s."),
2187
- modelObject=modelXbrl, concept=conceptSQName)
2188
- continue
2189
- conceptPrefix = conceptSQName.partition(":")[0]
2190
- if conceptPrefix not in namespaces:
2191
- error("oimce:unboundPrefix",
2192
- _("The concept QName prefix was not defined in namespaces: %(concept)s."),
2193
- modelObject=modelXbrl, concept=conceptSQName)
2194
- continue
2195
- conceptQn = qname(conceptSQName, namespaces)
2196
- if conceptQn.localName == "note" and conceptQn.namespaceURI in nsOims:
2197
- xbrlNoteTbl[id] = fact
2198
- if "language" not in dimensions:
2199
- error("oime:missingLanguageForNoteFact",
2200
- _("Missing language dimension for footnote fact %(id)s"),
2201
- modelObject=modelXbrl, id=id)
2202
- else:
2203
- factProduced.dimensionsUsed.add("language")
2204
- if isCSVorXL:
2205
- dimensions["noteId"] = id # infer this dimension
2206
- elif "noteId" not in dimensions:
2207
- error("oime:missingNoteIDDimension",
2208
- _("Missing noteId dimension for footnote fact %(id)s"),
2209
- modelObject=modelXbrl, id=id)
2210
- elif dimensions.get("noteId") != id:
2211
- error("oime:invalidNoteIDValue",
2212
- _("The noteId dimension value, %(noteId)s, must be the same as footnote fact id, %(id)s"),
2213
- modelObject=modelXbrl, id=id, noteId=dimensions["noteId"])
2214
- else:
2215
- noteFactIDsNotReferenced.add(id)
2216
- if dimensions.get("unit") and not isCSVorXL:
2217
- error("oime:misplacedUnitDimension",
2218
- _("The unit core dimension MUST NOT be present on footnote fact %(id)s: %(unit)s."),
2219
- modelObject=modelXbrl, id=id, unit=dimensions.get("unit"))
2220
- if fact.get("decimals") and not isCSVorXL:
2221
- error("oime:misplacedDecimalsProperty",
2222
- _("The decimals property MUST NOT be present on footnote fact %(id)s: %(decimals)s"),
2223
- modelObject=modelXbrl, id=id, decimals=decimals)
2224
- unexpectedDimensions = [d for d in dimensions if d in ("entity", "period") or ":" in d]
2225
- if unexpectedDimensions:
2226
- error("oime:misplacedNoteFactDimension",
2227
- _("Unexpected dimension(s) for footnote fact %(id)s: %(dimensions)s"),
2228
- modelObject=modelXbrl, id=id, dimensions=", ".join(sorted(unexpectedDimensions)))
2229
- try:
2230
- unacceptableTopElts = set()
2231
- unacceptablePrefixes = set()
2232
- valueXhtmlElts = etree.XML(htmlBodyTemplate.format(fact.get("value","")))
2233
- for elt in valueXhtmlElts.iterchildren():
2234
- if not elt.tag.startswith(xhtmlTagPrefix):
2235
- unacceptableTopElts.add(elt.tag)
2236
- for elt in valueXhtmlElts.iter():
2237
- if elt.tag.startswith(xhtmlTagPrefix) and elt.prefix:
2238
- unacceptablePrefixes.add(elt.prefix)
2239
- if unacceptableTopElts:
2240
- error("oime:invalidXHTMLFragment",
2241
- _("xbrl:note MUST have xhtml top level elements in the default xhtml namespace, fact %(id)s, elements %(elements)s"),
2242
- modelObject=modelXbrl, id=id, elements=", ".join(sorted(unacceptableTopElts)))
2243
- if unacceptablePrefixes:
2244
- error("oime:xhtmlElementInNonDefaultNamespace",
2245
- _("xbrl:note MUST have xhtml elements in the default xhtml namespace, fact %(id)s, non-default prefixes: %(prefixes)s"),
2246
- modelObject=modelXbrl, id=id, prefixes=", ".join(sorted(unacceptablePrefixes)))
2247
- except (etree.XMLSyntaxError,
2248
- UnicodeDecodeError) as err:
2249
- error("oime:invalidXHTMLFragment",
2250
- _("Xhtml error for footnote fact %(id)s: %(error)s"),
2251
- modelObject=modelXbrl, id=id, error=str(err))
2252
- continue
2253
- elif "noteId" in dimensions:
2254
- error("oime:misplacedNoteIDDimension",
2255
- _("Unexpected noteId dimension on non-footnote fact, id %(id)s"),
2256
- modelObject=modelXbrl, id=id, noteId=dimensions["noteId"])
2257
- concept = modelXbrl.qnameConcepts.get(conceptQn)
2258
- if concept is None:
2259
- error("oime:unknownConcept",
2260
- _("The concept QName could not be resolved with available DTS: %(concept)s."),
2261
- modelObject=modelXbrl, concept=conceptQn)
2262
- continue
2263
- attrs = {}
2264
- if ((concept.instanceOfType(UNSUPPORTED_DATA_TYPES) and not concept.instanceOfType(dtrSQNameNamesItemTypes))
2265
- or concept.isTuple):
2266
- error("oime:unsupportedConceptDataType",
2267
- _("Concept has unsupported data type, %(value)s: %(concept)s."),
2268
- modelObject=modelXbrl, concept=conceptSQName, value=fact["value"])
2269
- continue
2270
- elif concept.isItem:
2271
- if concept.isAbstract:
2272
- error("oime:valueForAbstractConcept",
2273
- _("Value provided for abstract concept by fact %(factId)s, concept %(concept)s."),
2274
- modelObject=modelXbrl, factId=id, concept=conceptSQName)
2275
- continue # skip creating fact because context would be bad
2276
- if "language" in dimensions:
2277
- lang = dimensions["language"]
2278
- if lang is INVALID_REFERENCE_TARGET:
2279
- factProduced.invalidReferenceTarget = "language"
2280
- continue
2281
- if concept.type.isOimTextFactType:
2282
- if isJSON and not lang.islower():
2283
- error("xbrlje:invalidLanguageCodeCase",
2284
- _("Language MUST be lower case: \"%(lang)s\", fact %(factId)s, concept %(concept)s."),
2285
- modelObject=modelXbrl, factId=id, concept=conceptSQName, lang=lang)
2286
- factProduced.dimensionsUsed.add("language")
2287
- attrs["{http://www.w3.org/XML/1998/namespace}lang"] = lang
2288
- elif not isCSVorXL:
2289
- error("oime:misplacedLanguageDimension",
2290
- _("Language \"%(lang)s\" provided for non-text concept by fact %(factId)s, concept %(concept)s."),
2291
- modelObject=modelXbrl, factId=id, concept=conceptSQName, lang=lang)
2292
- continue # skip creating fact because language would be bad
2293
- entityAsQn = entityNaQName
2294
- entitySQName = dimensions.get("entity")
2295
- if entitySQName is INVALID_REFERENCE_TARGET:
2296
- factProduced.invalidReferenceTarget = "entity"
2297
- continue
2298
- if entitySQName is not None and entitySQName is not NONE_CELL:
2299
- factProduced.dimensionsUsed.add("entity")
2300
- if not SQNamePattern.match(entitySQName):
2301
- error("oimce:invalidSQName",
2302
- _("Entity has an invalid value: %(entity)s."),
2303
- modelObject=modelXbrl, entity=entitySQName)
2304
- continue
2305
- entityPrefix = entitySQName.partition(":")[0]
2306
- if entityPrefix not in namespaces:
2307
- error("oimce:unboundPrefix",
2308
- _("Entity QName prefix was not defined in namespaces: %(entity)s."),
2309
- modelObject=modelXbrl, entity=entitySQName)
2310
- else:
2311
- entityAsQn = qname(entitySQName, namespaces)
2312
- if entityAsQn == entityNaQName:
2313
- error("oime:invalidUseOfReservedIdentifier",
2314
- _("The entity core dimension MUST NOT have a scheme of 'https://xbrl.org/.../entities' with an identifier of 'NA': %(entity)s."),
2315
- modelObject=modelXbrl, entity=entitySQName)
2316
- continue
2317
- if "period" in dimensions:
2318
- period = dimensions["period"]
2319
- if period is INVALID_REFERENCE_TARGET:
2320
- factProduced.invalidReferenceTarget = "period"
2321
- continue
2322
- elif period is NONE_CELL:
2323
- period = "forever"
2324
- elif period is None or not PeriodPattern.match(period):
2325
- error("xbrlce:invalidPeriodRepresentation" if isCSVorXL else "oimce:invalidPeriodRepresentation",
2326
- _("The fact %(factId)s, concept %(element)s has a lexically invalid period dateTime %(periodError)s"),
2327
- modelObject=modelXbrl, factId=id, element=conceptQn, periodError=period)
2328
- continue
2329
- else:
2330
- factProduced.dimensionsUsed.add("period")
2331
- else:
2332
- period = "forever"
2333
- cntxKey = ( # hashable context key
2334
- ("periodType", concept.periodType),
2335
- ("entity", entityAsQn),
2336
- ("period", period)) + tuple(sorted(
2337
- (dimName, dimVal["value"] if isinstance(dimVal,dict) else dimVal)
2338
- for dimName, dimVal in dimensions.items()
2339
- if ":" in dimName))
2340
- _start, _sep, _end = period.rpartition('/')
2341
- if period == "forever":
2342
- _periodType = "forever"
2343
- elif _start == _end or not _start:
2344
- _periodType = "instant"
2345
- else:
2346
- _periodType = "duration"
2347
- if concept.periodType == "instant" and _periodType == "forever":
2348
- error("oime:missingPeriodDimension",
2349
- _("Missing period for %(periodType)s fact %(factId)s."),
2350
- modelObject=modelXbrl, factId=id, periodType=concept.periodType, period=period)
2351
- continue # skip creating fact because context would be bad
2352
- elif ((concept.periodType == "duration" and (_periodType != "forever" and (not _start or _start == _end))) or
2353
- (concept.periodType == "instant" and _start and _start != _end)):
2354
- error("oime:invalidPeriodDimension",
2355
- _("Invalid period for %(periodType)s fact %(factId)s period %(period)s."),
2356
- modelObject=modelXbrl, factId=id, periodType=concept.periodType, period=period)
2357
- continue # skip creating fact because context would be bad
2358
- elif cntxKey in cntxTbl:
2359
- _cntx = cntxTbl[cntxKey]
2360
- for dimName, dimVal in cntxKey[3:]:
2361
- factProduced.dimensionsUsed.add(dimName)
2362
- else:
2363
- cntxId = 'c-{:02}'.format(len(cntxTbl) + 1)
2364
- qnameDims = {}
2365
- hasDimErr = False
2366
- for dimName, dimVal in dimensions.items():
2367
- if ":" in dimName:
2368
- if dimVal is INVALID_REFERENCE_TARGET:
2369
- factProduced.invalidReferenceTarget = dimName
2370
- hasDimErr = True
2371
- break
2372
- factProduced.dimensionsUsed.add(dimName)
2373
- dimQname = qname(dimName, namespaces)
2374
- if isJSON and dimQname.namespaceURI in nsOims:
2375
- error("xbrlje:invalidJSONStructure",
2376
- _("Fact %(factId)s taxonomy-defined dimension QName must not be xbrl prefixed: %(qname)s."),
2377
- modelObject=modelXbrl, factId=id, qname=dimQname)
2378
- continue
2379
- dimConcept = modelXbrl.qnameConcepts.get(dimQname)
2380
- if dimConcept is None:
2381
- error("oime:unknownDimension",
2382
- _("Fact %(factId)s taxonomy-defined dimension QName not be resolved with available DTS: %(qname)s."),
2383
- modelObject=modelXbrl, factId=id, qname=dimQname)
2384
- continue
2385
- if dimVal is None:
2386
- memberAttrs = {"{http://www.w3.org/2001/XMLSchema-instance}nil": "true"}
2387
- else:
2388
- memberAttrs = None
2389
- if isinstance(dimVal, dict):
2390
- dimVal = dimVal["value"]
2391
- elif dimVal is not None:
2392
- dimVal = str(dimVal) # may be int or boolean
2393
- if dimConcept.isExplicitDimension:
2394
- mem = qname(dimVal, namespaces)
2395
- if mem is None:
2396
- error("{}:invalidDimensionValue".format(valErrPrefix),
2397
- _("Fact %(factId)s taxonomy-defined explicit dimension value is invalid: %(memberQName)s."),
2398
- modelObject=modelXbrl, factId=id, memberQName=dimVal)
2399
- continue
2400
- memConcept = modelXbrl.qnameConcepts.get(mem)
2401
- if memConcept is not None and modelXbrl.dimensionDefaultConcepts.get(dimConcept) == memConcept:
2402
- error("{}:invalidDimensionValue".format("oime" if valErrPrefix == "xbrlje" else valErrPrefix),
2403
- _("Fact %(factId)s taxonomy-defined explicit dimension value must not be the default member: %(memberQName)s."),
2404
- modelObject=modelXbrl, factId=id, memberQName=dimVal)
2405
- continue
2406
- elif dimConcept.isTypedDimension:
2407
- # a modelObject xml element is needed for all of the instance functions to manage the typed dim
2408
- if dimConcept.typedDomainElement.baseXsdType in ("ENTITY", "ENTITIES", "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "NOTATION") or (
2409
- dimConcept.typedDomainElement.instanceOfType(dtrPrefixedContentTypes) and not dimConcept.typedDomainElement.instanceOfType(dtrSQNameNamesTypes)) or (
2410
- dimConcept.typedDomainElement.type is not None and
2411
- dimConcept.typedDomainElement.type.qname != XbrlConst.qnXbrliDateUnion and
2412
- (dimConcept.typedDomainElement.type.localName == "complexType" or
2413
- any(c.localName in ("union","list") for c in dimConcept.typedDomainElement.type.iterchildren()))):
2414
- error("oime:unsupportedDimensionDataType",
2415
- _("Fact %(factId)s taxonomy-defined typed dimension value is not supported: %(memberQName)s."),
2416
- modelObject=modelXbrl, factId=id, memberQName=dimVal)
2417
- continue
2418
- if (canonicalValuesFeature and dimVal is not None and
2419
- not CanonicalXmlTypePattern.get(dimConcept.typedDomainElement.baseXsdType, NoCanonicalPattern).match(dimVal)):
2420
- error("xbrlje:nonCanonicalValue",
2421
- _("Numeric typed dimension must have canonical %(type)s value \"%(value)s\": %(concept)s."),
2422
- modelObject=modelXbrl, type=dimConcept.typedDomainElement.baseXsdType, concept=dimConcept, value=dimVal)
2423
- mem = addChild(modelXbrl.modelDocument, dimConcept.typedDomainElement.qname, text=dimVal, attributes=memberAttrs, appendChild=False)
2424
- else:
2425
- mem = None # absent typed dimension
2426
- if mem is not None:
2427
- qnameDims[dimQname] = DimValuePrototype(modelXbrl, None, dimQname, mem, contextElement)
2428
- if hasDimErr:
2429
- continue
2430
- try:
2431
- _start, _sep, _end = period.rpartition('/')
2432
- if period == "forever":
2433
- startDateTime = endDateTime = None
2434
- elif _start == _end or not _start:
2435
- startDateTime = None
2436
- endDateTime = dateTime(_end, type=DATETIME)
2437
- else:
2438
- startDateTime = dateTime(_start, type=DATETIME)
2439
- endDateTime = dateTime(_end, type=DATETIME)
2440
- numFactCreationXbrlErrors -= len(modelXbrl.errors) # track any xbrl validation errors
2441
- prevErrLen = len(modelXbrl.errors)
2442
- _cntx = modelXbrl.createContext(
2443
- entityAsQn.namespaceURI,
2444
- entityAsQn.localName,
2445
- _periodType,
2446
- startDateTime,
2447
- endDateTime,
2448
- None, # no dimensional validity checking (like formula does)
2449
- qnameDims, [], [],
2450
- id=cntxId)
2451
- if len(modelXbrl.errors) > prevErrLen:
2452
- if any(err == "xmlSchema:valueError" for err in modelXbrl.errors[prevErrLen:]):
2453
- error("{}:invalidDimensionValue".format(valErrPrefix),
2454
- _("Fact %(factId)s taxonomy-defined dimension value errors noted above."),
2455
- modelObject=modelXbrl, factId=id)
2456
- continue
2457
- numFactCreationXbrlErrors += sum(err != "xmlSchema:valueError" for err in modelXbrl.errors[prevErrLen:])
2458
- except ValueError as err:
2459
- error("xbrlce:invalidPeriodRepresentation" if isCSVorXL else "oimce:invalidPeriodRepresentation",
2460
- _("Invalid period for fact %(factId)s period %(period)s, %(error)s."),
2461
- modelObject=modelXbrl, factId=id, period=period, error=err)
2462
- continue
2463
- cntxTbl[cntxKey] = _cntx
2464
- if firstCntxUnitFactElt is None:
2465
- firstCntxUnitFactElt = _cntx
2466
- unitKey = dimensions.get("unit")
2467
- if concept.isNumeric:
2468
- if unitKey is INVALID_REFERENCE_TARGET:
2469
- factProduced.invalidReferenceTarget = "unit"
2470
- continue
2471
- if unitKey == "xbrli:pure":
2472
- error("oime:illegalPureUnit",
2473
- _("Unit MUST NOT have single numerator measure xbrli:pure with no denominators."),
2474
- modelObject=modelXbrl, unit=unitKey)
2475
- continue
2476
- if unitKey: # not empty cells
2477
- factProduced.dimensionsUsed.add("unit")
2478
- if (unitKey or None) in unitTbl: # either None or EMPTY_CELL match None for default pure unit
2479
- _unit = unitTbl[unitKey or None]
2480
- else:
2481
- _unit = None
2482
- # validate unit
2483
- if unitKey and not UnitPattern.match( PrefixedQName.sub(UnitPrefixedQNameSubstitutionChar, unitKey) ):
2484
- error("oimce:invalidUnitStringRepresentation",
2485
- _("Unit string representation is lexically invalid, %(unit)s"),
2486
- modelObject=modelXbrl, unit=unitKey)
2487
- continue
2488
- else:
2489
- if not unitKey:
2490
- _muls = [XbrlConst.qnXbrliPure]
2491
- _divs = []
2492
- unitKey = None # use None for pure unit key (may be either no value or empty cell value)
2493
- else:
2494
- _mul, _sep, _div = unitKey.partition('/')
2495
- if _mul.startswith('('):
2496
- _mul = _mul[1:-1]
2497
- _muls = [u for u in _mul.split('*') if u]
2498
- if _div.startswith('('):
2499
- _div = _div[1:-1]
2500
- _divs = [u for u in _div.split('*') if u]
2501
- if _muls != sorted(_muls) or _divs != sorted(_divs):
2502
- error("oimce:invalidUnitStringRepresentation",
2503
- _("Unit string representation measures are not in alphabetical order, %(unit)s"),
2504
- modelObject=modelXbrl, unit=unitKey)
2505
- try:
2506
- mulQns = [qname(u, namespaces, prefixException=OIMException("oimce:unboundPrefix",
2507
- _("Unit prefix is not declared: %(unit)s"),
2508
- unit=u))
2509
- for u in _muls]
2510
- divQns = [qname(u, namespaces, prefixException=OIMException("oimce:unboundPrefix",
2511
- _("Unit prefix is not declared: %(unit)s"),
2512
- unit=u))
2513
- for u in _divs]
2514
- unitId = 'u-{:02}'.format(len(unitTbl) + 1)
2515
- for _measures in mulQns, divQns:
2516
- for _measure in _measures:
2517
- addQnameValue(modelXbrl.modelDocument, _measure)
2518
- _unit = modelXbrl.createUnit(mulQns, divQns, id=unitId)
2519
- if firstCntxUnitFactElt is None:
2520
- firstCntxUnitFactElt = _unit
2521
- except OIMException as ex:
2522
- error(ex.code, ex.message, modelObject=modelXbrl, **ex.msgArgs)
2523
- unitTbl[unitKey] = _unit
2524
- else:
2525
- _unit = None
2526
- if unitKey is not None and not isCSVorXL:
2527
- error("oime:misplacedUnitDimension",
2528
- _("The unit core dimension MUST NOT be present on non-numeric facts: %(concept)s, unit %(unit)s."),
2529
- modelObject=modelXbrl, concept=conceptSQName, unit=unitKey)
2530
-
2531
- attrs["contextRef"] = _cntx.id
2532
-
2533
- if fact.get("value") is None:
2534
- if not concept.isNillable:
2535
- error("{}:invalidFactValue".format("oime" if isJSON else valErrPrefix),
2536
- _("Nil value applied to non-nillable concept: %(concept)s."),
2537
- modelObject=modelXbrl, concept=conceptSQName)
2538
- continue
2539
- attrs[XbrlConst.qnXsiNil] = "true"
2540
- text = None
2541
- elif concept.isEnumeration2Item:
2542
- text = fact["value"]
2543
- if concept.instanceOfType(XbrlConst.qnEnumerationSetItemType2020):
2544
- if len(text):
2545
- qnames = text.split(" ")
2546
- else:
2547
- qnames = () # empty enumerations set
2548
- else: # single value may be a QName with whitespaces
2549
- qnames = (text.strip(),)
2550
- expandedNames = set()
2551
- if canonicalValuesFeature and not all(qnames[i] < qnames[i+1] for i in range(len(qnames)-1)):
2552
- error("xbrlje:nonCanonicalValue",
2553
- _("Enumeration item must be canonically ordered, %(value)s: %(concept)s."),
2554
- modelObject=modelXbrl, concept=conceptSQName, value=fact["value"])
2555
- isFactValid = True
2556
- for qn in qnames:
2557
- if not PrefixedQName.match(qn):
2558
- isFactValid = False
2559
- else:
2560
- _qname = qname(qn, namespaces)
2561
- if not _qname:
2562
- error("oimce:unboundPrefix",
2563
- _("Enumeration item QName prefix was not defined in namespaces, %(qname)s: %(concept)s."),
2564
- modelObject=modelXbrl, concept=conceptSQName, qname=qn)
2565
- continue
2566
- else:
2567
- expandedNames.add(_qname.expandedName)
2568
- if isFactValid:
2569
- text = " ".join(sorted(expandedNames))
2570
- else:
2571
- error("{}:invalidFactValue".format(valErrPrefix),
2572
- _("Enumeration item must be %(canonicalOrdered)slist of QNames: %(concept)s."),
2573
- modelObject=modelXbrl, concept=conceptSQName, canonicalOrdered="a canonical ordered " if canonicalValuesFeature else "")
2574
- continue
2575
- else:
2576
- text = fact["value"]
2577
- if (canonicalValuesFeature and text is not None and
2578
- not CanonicalXmlTypePattern.get(concept.baseXsdType, NoCanonicalPattern).match(text)):
2579
- error("xbrlje:nonCanonicalValue",
2580
- _("Item must have canonical %(type)s value \"%(value)s\": %(concept)s."),
2581
- modelObject=modelXbrl, type=concept.baseXsdType, concept=conceptSQName, value=text)
2582
-
2583
- decimals = fact.get("decimals")
2584
- if concept.isNumeric:
2585
- if isCSVorXL and isinstance(text, str): # don't check for suffix if not CSV/XL or None or int
2586
- _number, _sep, _decimals = text.partition("d")
2587
- if _sep:
2588
- if decimalsSuffixPattern.match(text):
2589
- decimals = _decimals.strip()
2590
- text = _number.strip()
2591
- else:
2592
- error("xbrlce:invalidDecimalsSuffix",
2593
- _("Fact %(factId)s has invalid decimals \"%(decimals)s\""),
2594
- modelObject=modelXbrl, factId=id, decimals=_sep+_decimals)
2595
- continue # skip processing this fact
2596
- elif decimals is not None:
2597
- if decimals is INVALID_REFERENCE_TARGET:
2598
- factProduced.invalidReferenceTarget = "decimals"
2599
- continue
2600
- factProduced.dimensionsUsed.add("decimals")
2601
- if _unit is None:
2602
- continue # skip creating fact because unit was invalid
2603
- attrs["unitRef"] = _unit.id
2604
- if text is not None: # no decimals for nil value
2605
- attrs["decimals"] = decimals if decimals is not None else "INF"
2606
- elif decimals is not None:
2607
- error("oime:misplacedDecimalsProperty",
2608
- _("The decimals property MUST NOT be present on nil facts: %(concept)s, decimals %(decimals)s"),
2609
- modelObject=modelXbrl, concept=conceptSQName, decimals=decimals)
2610
- continue
2611
- elif decimals is not None and not isCSVorXL:
2612
- # includes nil facts for JSON (but not CSV)
2613
- error("oime:misplacedDecimalsProperty",
2614
- _("The decimals property MUST NOT be present on non-numeric facts: %(concept)s, decimals %(decimals)s"),
2615
- modelObject=modelXbrl, concept=conceptSQName, decimals=decimals)
2616
- else:
2617
- text = None #tuple
2618
-
2619
- attrs["id"] = id
2620
- if "id" not in fact: # needed for footnote generation
2621
- fact["id"] = id
2622
-
2623
- # is value a QName?
2624
- if concept.baseXbrliType == "QNameItemType": # renormalize prefix of instance fact
2625
- text = addQnameValue(modelXbrl.modelDocument, qname(text.strip(), namespaces))
2626
-
2627
- prevErrLen = len(modelXbrl.errors) # track any xbrl validation errors
2628
- factProduced.modelFact = f = modelXbrl.createFact(conceptQn, attributes=attrs, text=text, validate=False)
2629
- if firstCntxUnitFactElt is None:
2630
- firstCntxUnitFactElt = f
2631
-
2632
- xmlValidate(modelXbrl, f)
2633
- if len(modelXbrl.errors) > prevErrLen:
2634
- numFactCreationXbrlErrors += sum(err != "xmlSchema:valueError" for err in modelXbrl.errors[prevErrLen:])
2635
- if any(err == "xmlSchema:valueError" for err in modelXbrl.errors[prevErrLen:]):
2636
- error("{}:invalidFactValue".format(valErrPrefix),
2637
- _("Fact %(factId)s value error noted above."),
2638
- modelObject=modelXbrl, factId=id)
2639
-
2640
- currentAction = "creating footnotes"
2641
- footnoteLinks = OrderedDict() # ELR elements
2642
- factLocs = {} # index by (linkrole, factId)
2643
- footnoteLinkNotes = defaultdict(set) # linkrole: noteIds
2644
- # footnoteNbr = 0
2645
- locNbr = 0
2646
- definedInstanceRoles = set()
2647
- undefinedFootnoteTypes = set()
2648
- undefinedFootnoteGroups = set()
2649
- undefinedLinkTargets = set()
2650
- undefinedLinkSources = set() # csv only
2651
- footnotesIdTargets = set()
2652
- for factOrFootnote in footnotes:
2653
- if isJSON:
2654
- for ftGroups in factOrFootnote.get("links", {}).values():
2655
- for ftTgtIds in ftGroups.values():
2656
- for tgtId in ftTgtIds:
2657
- if tgtId in xbrlNoteTbl:
2658
- footnotesIdTargets.add(tgtId)
2659
- elif isCSVorXL: # footnotes contains footnote objects
2660
- for ftGroups in factOrFootnote.values():
2661
- for ftSrcIdTgtIds in ftGroups.values():
2662
- for ftTgtIds in ftSrcIdTgtIds.values():
2663
- for tgtId in ftTgtIds:
2664
- footnotesIdTargets.add(tgtId)
2665
- for factOrFootnote in footnotes:
2666
- if isJSON:
2667
- factFootnotes = []
2668
- for ftType, ftGroups in factOrFootnote.get("links", {}).items():
2669
- ftSrcId = factOrFootnote.get("id")
2670
- if ftSrcId is None:
2671
- ftSrcId = factOrFootnote.get("dimensions",EMPTY_DICT).get("xbrl:noteId")
2672
- if ftType not in linkTypes:
2673
- undefinedFootnoteTypes.add(ftType)
2674
- else:
2675
- for ftGroup, ftTgtIds in ftGroups.items():
2676
- if ftGroup not in linkGroups:
2677
- undefinedFootnoteGroups.add(ftGroup)
2678
- else:
2679
- footnote = {"id": ftSrcId,
2680
- "footnoteGroup": linkGroups[ftGroup],
2681
- "footnoteType": linkTypes[ftType]}
2682
- for tgtId in ftTgtIds:
2683
- if tgtId in xbrlNoteTbl:
2684
- footnote.setdefault("noteRefs", []).append(tgtId)
2685
- noteFactIDsNotReferenced.discard(tgtId)
2686
- elif tgtId in modelXbrl.modelDocument.idObjects:
2687
- footnote.setdefault("factRefs", []).append(tgtId)
2688
- else:
2689
- undefinedLinkTargets.add(tgtId)
2690
- factFootnotes.append(footnote)
2691
- elif isCSVorXL: # footnotes contains footnote objects
2692
- factFootnotes = []
2693
- for ftType, ftGroups in factOrFootnote.items():
2694
- if ftType not in linkTypes:
2695
- undefinedFootnoteTypes.add(ftType)
2696
- else:
2697
- for ftGroup, ftSrcIdTgtIds in ftGroups.items():
2698
- if ftGroup not in linkGroups:
2699
- undefinedFootnoteGroups.add(ftGroup)
2700
- else:
2701
- for ftSrcId, ftTgtIds in ftSrcIdTgtIds.items():
2702
- footnote = {"id": ftSrcId,
2703
- "footnoteGroup": linkGroups[ftGroup],
2704
- "footnoteType": linkTypes[ftType]}
2705
- if ftSrcId not in modelXbrl.modelDocument.idObjects:
2706
- undefinedLinkSources.add(ftSrcId)
2707
- for tgtId in ftTgtIds:
2708
- if tgtId in xbrlNoteTbl:
2709
- footnote.setdefault("noteRefs", []).append(tgtId)
2710
- noteFactIDsNotReferenced.discard(tgtId)
2711
- elif tgtId in modelXbrl.modelDocument.idObjects:
2712
- footnote.setdefault("factRefs", []).append(tgtId)
2713
- else:
2714
- undefinedLinkTargets.add(tgtId)
2715
- factFootnotes.append(footnote)
2716
- for footnote in factFootnotes:
2717
- factId = footnote["id"]
2718
- linkrole = footnote["footnoteGroup"]
2719
- arcrole = footnote["footnoteType"]
2720
- skipThisFootnote = False
2721
- if not factId or not linkrole or not arcrole or not (
2722
- footnote.get("factRefs") or footnote.get("footnote") is not None or footnote.get("noteRefs") is not None):
2723
- if not linkrole:
2724
- warning("xbrlje:unknownLinkGroup",
2725
- _("FootnoteId has no linkrole %(footnoteId)s."),
2726
- modelObject=modelXbrl, footnoteId=footnote.get("footnoteId"))
2727
- if not arcrole:
2728
- warning("xbrlje:unknownLinkType",
2729
- _("FootnoteId has no arcrole %(footnoteId)s."),
2730
- modelObject=modelXbrl, footnoteId=footnote.get("footnoteId"))
2731
- continue
2732
- for refType, refValue, roleTypes, lrrRoles in (("role", linkrole, modelXbrl.roleTypes, lrrRoleHrefs),
2733
- ("arcrole", arcrole, modelXbrl.arcroleTypes, lrrArcroleHrefs)):
2734
- if not (XbrlConst.isStandardRole(refValue) or XbrlConst.isStandardArcrole(refValue)):
2735
- if refValue not in definedInstanceRoles:
2736
- if refValue in roleTypes or refValue in lrrRoles:
2737
- definedInstanceRoles.add(refValue)
2738
- if refValue in roleTypes:
2739
- hrefElt = roleTypes[refValue][0]
2740
- href = hrefElt.modelDocument.uri + "#" + hrefElt.id
2741
- else:
2742
- href = lrrRoles[refValue]
2743
- elt = addChild(modelXbrl.modelDocument.xmlRootElement,
2744
- qname(link, refType+"Ref"),
2745
- attributes=(("{http://www.w3.org/1999/xlink}href", href),
2746
- ("{http://www.w3.org/1999/xlink}type", "simple")),
2747
- beforeSibling=firstCntxUnitFactElt)
2748
- href = modelXbrl.modelDocument.discoverHref(elt)
2749
- if href:
2750
- _elt, hrefDoc, hrefId = href
2751
- _defElt = hrefDoc.idObjects.get(hrefId)
2752
- if _defElt is not None:
2753
- _uriAttrName = refType + "URI"
2754
- _uriAttrValue = _defElt.get(_uriAttrName)
2755
- if _uriAttrValue:
2756
- elt.set(_uriAttrName, _uriAttrValue)
2757
- else:
2758
- error("xbrlxe:nonStandardRoleDefinitionNotInDTS",
2759
- _("Footnote %(sourceId)s %(roleType)s %(role)s not defined in DTS"),
2760
- modelObject=modelXbrl, sourceId=factId, roleType=refType, role=refValue)
2761
- skipThisFootnote = True
2762
- if skipThisFootnote:
2763
- continue
2764
- if linkrole not in footnoteLinks:
2765
- footnoteLinks[linkrole] = addChild(modelXbrl.modelDocument.xmlRootElement,
2766
- XbrlConst.qnLinkFootnoteLink,
2767
- attributes={"{http://www.w3.org/1999/xlink}type": "extended",
2768
- "{http://www.w3.org/1999/xlink}role": linkrole})
2769
- footnoteLink = footnoteLinks[linkrole]
2770
- factIDs = (factId,)
2771
- if factId in xbrlNoteTbl: # factId is a note, not a fact
2772
- fromLabel = "f_{}".format(factId)
2773
- factLocs[(linkrole, factIDs)] = fromLabel
2774
- noteFactIDsNotReferenced.discard(factId)
2775
- elif (linkrole, factIDs) not in factLocs:
2776
- locNbr += 1
2777
- locLabel = "l_{:02}".format(locNbr)
2778
- factLocs[(linkrole, factIDs)] = locLabel
2779
- addChild(footnoteLink, XbrlConst.qnLinkLoc,
2780
- attributes={XLINKTYPE: "locator",
2781
- XLINKHREF: "#" + factId,
2782
- XLINKLABEL: locLabel})
2783
- locFromLabel = factLocs[(linkrole, factIDs)]
2784
- if "noteRefs" in footnote:
2785
- # footnoteNbr += 1
2786
- # footnoteToLabel = "f_{:02}".format(footnoteNbr)
2787
- for noteId in footnote.get("noteRefs"):
2788
- footnoteToLabel = "f_{}".format(noteId)
2789
- noteFactIDsNotReferenced.discard(noteId)
2790
- if noteId not in footnoteLinkNotes[linkrole]:
2791
- footnoteLinkNotes[linkrole].add(noteId)
2792
- xbrlNote = xbrlNoteTbl[noteId]
2793
- attrs = {XLINKTYPE: "resource",
2794
- XLINKLABEL: footnoteToLabel,
2795
- "id": idDeduped(modelXbrl, noteId),
2796
- # "oimNoteId": noteId
2797
- }
2798
- #if noteId in footnotesIdTargets: # footnote resource is target of another footnote loc
2799
- # attrs["id"] = noteId
2800
- try:
2801
- if "dimensions" in xbrlNote:
2802
- attrs[XMLLANG] = xbrlNote["dimensions"]["language"]
2803
- elif "aspects" in xbrlNote:
2804
- attrs[XMLLANG] = xbrlNote["aspects"]["language"]
2805
- except KeyError:
2806
- pass
2807
- tgtElt = addChild(footnoteLink, XbrlConst.qnLinkFootnote, attributes=attrs)
2808
- srcElt = etree.fromstring("<footnote xmlns=\"http://www.w3.org/1999/xhtml\">{}</footnote>"
2809
- .format(xbrlNote["value"]), parser=modelXbrl.modelDocument.parser)
2810
- if srcElt.__len__() > 0: # has html children
2811
- setXmlns(modelXbrl.modelDocument, "xhtml", "http://www.w3.org/1999/xhtml")
2812
- copyIxFootnoteHtml(srcElt, tgtElt, withText=True, isContinChainElt=False)
2813
- xmlValidate(modelXbrl, tgtElt)
2814
- footnoteArc = addChild(footnoteLink,
2815
- XbrlConst.qnLinkFootnoteArc,
2816
- attributes={XLINKTYPE: "arc",
2817
- XLINKARCROLE: arcrole,
2818
- XLINKFROM: locFromLabel,
2819
- XLINKTO: footnoteToLabel})
2820
- if "factRefs" in footnote:
2821
- factRef = footnote.get("factRefs")
2822
- fact2IDs = tuple(sorted(factRef))
2823
- if (linkrole, fact2IDs) not in factLocs:
2824
- locNbr += 1
2825
- locLabel = "l_{:02}".format(locNbr)
2826
- factLocs[(linkrole, fact2IDs)] = locLabel
2827
- for factId in fact2IDs:
2828
- addChild(footnoteLink, XbrlConst.qnLinkLoc,
2829
- attributes={XLINKTYPE: "locator",
2830
- XLINKHREF: "#" + factId,
2831
- XLINKLABEL: locLabel})
2832
- footnoteToLabel = factLocs[(linkrole, fact2IDs)]
2833
- footnoteArc = addChild(footnoteLink,
2834
- XbrlConst.qnLinkFootnoteArc,
2835
- attributes={XLINKTYPE: "arc",
2836
- XLINKARCROLE: arcrole,
2837
- XLINKFROM: locFromLabel,
2838
- XLINKTO: footnoteToLabel})
2839
- if arcrole == factFootnote:
2840
- error("oime:illegalStandardFootnoteTarget",
2841
- _("Standard footnote %(sourceId)s targets must be an xbrl:note, targets %(targetIds)s."),
2842
- modelObject=modelXbrl, sourceId=factId, targetIds=", ".join(fact2IDs))
2843
- if noteFactIDsNotReferenced:
2844
- error("oime:unusedNoteFact",
2845
- _("Note facts MUST be referenced by at least one link group, IDs: %(noteFactIds)s."),
2846
- modelObject=modelXbrl, noteFactIds=", ".join(sorted(noteFactIDsNotReferenced)))
2847
- if footnoteLinks:
2848
- modelXbrl.modelDocument.linkbaseDiscover(footnoteLinks.values(), inInstance=True)
2849
-
2850
- if undefinedLinkSources:
2851
- error("{}:unknownLinkSource".format(errPrefix),
2852
- _("These link sources are not defined in facts: %(ftTargets)s."),
2853
- modelObject=modelXbrl, ftTargets=", ".join(sorted(undefinedLinkSources)))
2854
- if undefinedLinkTargets:
2855
- error("{}:unknownLinkTarget".format(errPrefix),
2856
- _("These link targets are not defined in facts: %(ftTargets)s."),
2857
- modelObject=modelXbrl, ftTargets=", ".join(sorted(undefinedLinkTargets)))
2858
- if undefinedFootnoteTypes:
2859
- error("{}:unknownLinkType".format(errPrefix),
2860
- _("These footnote types are not defined in footnoteTypes: %(ftTypes)s."),
2861
- modelObject=modelXbrl, ftTypes=", ".join(sorted(undefinedFootnoteTypes)))
2862
- if undefinedFootnoteGroups:
2863
- error("{}:unknownLinkGroup".format(errPrefix),
2864
- _("These footnote groups are not defined in footnoteGroups: %(ftGroups)s."),
2865
- modelObject=modelXbrl, ftGroups=", ".join(sorted(undefinedFootnoteGroups)))
2866
-
2867
- checkForDuplicates(modelXbrl, allowedDuplicatesFeature, footnotesIdTargets)
2868
-
2869
- currentAction = "done loading facts and footnotes"
2870
-
2871
- if numFactCreationXbrlErrors:
2872
- error("oime:invalidXBRL",
2873
- _("%(count)s XBRL errors noted above."),
2874
- modelObject=modelXbrl, count=numFactCreationXbrlErrors)
2875
-
2876
-
2877
- #cntlr.addToLog("Completed in {0:.2} secs".format(time.time() - startedAt),
2878
- # messageCode="loadFromExcel:info")
2879
- except NotOIMException as ex:
2880
- _return = ex # not an OIM document
2881
- except Exception as ex:
2882
- _return = ex
2883
- if isinstance(ex, OIMException):
2884
- if ex.code and ex.message:
2885
- error(ex.code, ex.message, modelObject=modelXbrl, **ex.msgArgs)
2886
- else:
2887
- error("arelleOIMloader:error",
2888
- "Error while %(action)s, error %(error)s\n traceback %(traceback)s",
2889
- modelObject=modelXbrl, action=currentAction, error=ex,
2890
- traceback=traceback.format_tb(sys.exc_info()[2]))
2891
-
2892
- global lastFilePath, lastFilePath
2893
- lastFilePath = None
2894
- lastFilePathIsOIM = False
2895
- return _return
2896
-
2897
- lastFilePath = None
2898
- lastFilePathIsOIM = False
2899
-
2900
- def isOimLoadable(modelXbrl, mappedUri, normalizedUri, filepath, **kwargs):
2901
- global lastFilePath, lastFilePathIsOIM
2902
- lastFilePath = filepath
2903
- lastFilePathIsOIM = False
2904
- _ext = os.path.splitext(filepath)[1]
2905
- if _ext in (".csv", ".json", ".xlsx", ".xls"):
2906
- lastFilePathIsOIM = True
2907
- elif isHttpUrl(normalizedUri) and '?' in _ext: # query parameters and not .json, may be JSON anyway
2908
- with io.open(filepath, 'rt', encoding='utf-8') as f:
2909
- _fileStart = f.read(4096)
2910
- if _fileStart and re_match(r"\s*\{\s*\"documentType\":\s*\"http:\\+/\\+/www.xbrl.org\\+/WGWD\\+/YYYY-MM-DD\\+/xbrl-json\"", _fileStart):
2911
- lastFilePathIsOIM = True
2912
- return lastFilePathIsOIM
2913
-
2914
- def oimLoader(modelXbrl, mappedUri, filepath, *args, **kwargs):
2915
- if filepath != lastFilePath or not lastFilePathIsOIM:
2916
- return None # not an OIM file
2917
-
2918
- cntlr = modelXbrl.modelManager.cntlr
2919
- cntlr.showStatus(_("Loading OIM file: {0}").format(os.path.basename(filepath)))
2920
- doc = loadFromOIM(cntlr, modelXbrl.error, modelXbrl.warning, modelXbrl, filepath, mappedUri)
2921
- if doc is None:
2922
- return None # not an OIM file
2923
- modelXbrl.loadedFromOIM = True
2924
- modelXbrl.loadedFromOimErrorCount = len(modelXbrl.errors)
2925
- return doc
2926
-
2927
- def guiXbrlLoaded(cntlr, modelXbrl, attach, *args, **kwargs):
2928
- if cntlr.hasGui and getattr(modelXbrl, "loadedFromOIM", False):
2929
- from arelle import ModelDocument
2930
- from tkinter.filedialog import askdirectory
2931
- instanceFile = cntlr.uiFileDialog("save",
2932
- title=_("arelle - Save XBRL instance document"),
2933
- initialdir=cntlr.config.setdefault("outputInstanceDir","."),
2934
- filetypes=[(_("XBRL file .xbrl"), "*.xbrl"), (_("XBRL file .xml"), "*.xml")],
2935
- defaultextension=".xbrl")
2936
- if not instanceFile:
2937
- return False
2938
- cntlr.config["outputInstanceDir"] = os.path.dirname(instanceFile)
2939
- cntlr.saveConfig()
2940
- if instanceFile:
2941
- modelXbrl.modelDocument.save(instanceFile, updateFileHistory=False)
2942
- cntlr.showStatus(_("Saving XBRL instance: {0}").format(os.path.basename(instanceFile)))
2943
- cntlr.showStatus(_("OIM loading completed"), 3500)
2944
-
2945
- def cmdLineXbrlLoaded(cntlr, options, modelXbrl, *args, **kwargs):
2946
- if options.saveOIMinstance and getattr(modelXbrl, "loadedFromOIM", False):
2947
- doc = modelXbrl.modelDocument
2948
- cntlr.showStatus(_("Saving XBRL instance: {0}").format(doc.basename))
2949
- responseZipStream = kwargs.get("responseZipStream")
2950
- if responseZipStream is not None:
2951
- _zip = zipfile.ZipFile(responseZipStream, "a", zipfile.ZIP_DEFLATED, True)
2952
- else:
2953
- _zip = None
2954
- doc.save(options.saveOIMinstance, _zip)
2955
- if responseZipStream is not None:
2956
- _zip.close()
2957
- responseZipStream.seek(0)
2958
-
2959
- def validateFinally(val, *args, **kwargs):
12
+ def validateFinally(val: ValidateXbrl, *args: Any, **kwargs: Any) -> None:
2960
13
  modelXbrl = val.modelXbrl
2961
- if getattr(modelXbrl, "loadedFromOIM", False):
2962
- if modelXbrl.loadedFromOimErrorCount < len(modelXbrl.errors):
2963
- modelXbrl.error("oime:invalidTaxonomy",
2964
- _("XBRL validation errors were logged for this instance."),
2965
- modelObject=modelXbrl)
2966
- else:
2967
- # validate xBRL-XML instances
2968
- fractionFacts = []
2969
- tupleFacts = []
2970
- precisionZeroFacts = []
2971
- contextsInUse = set()
2972
- for f in modelXbrl.factsInInstance: # facts in document order (no sorting required for messages)
2973
- concept = f.concept
2974
- if concept is not None:
2975
- if concept.isFraction:
2976
- fractionFacts.append(f)
2977
- elif concept.isTuple:
2978
- tupleFacts.append(f)
2979
- elif concept.isNumeric:
2980
- if f.precision is not None and precisionZeroPattern.match(f.precision):
2981
- precisionZeroFacts.append(f)
2982
- context = f.context
2983
- if context is not None:
2984
- contextsInUse.add(context)
2985
- if fractionFacts:
2986
- modelXbrl.error("xbrlxe:unsupportedFraction", # this pertains only to xBRL-XML validation (JSON and CSV were checked during loading when loadedFromOIM is True)
2987
- _("Instance has %(count)s facts with fraction facts"),
2988
- modelObject=fractionFacts, count=len(fractionFacts))
2989
- if tupleFacts:
2990
- modelXbrl.error("xbrlxe:unsupportedTuple",
2991
- _("Instance has %(count)s tuple facts"),
2992
- modelObject=tupleFacts, count=len(tupleFacts))
2993
- if precisionZeroFacts:
2994
- modelXbrl.error("xbrlxe:unsupportedZeroPrecisionFact",
2995
- _("Instance has %(count)s precision zero facts"),
2996
- modelObject=precisionZeroFacts, count=len(precisionZeroFacts))
2997
- containers = {"segment", "scenario"}
2998
- dimContainers = set(t for c in contextsInUse for t in containers if c.dimValues(t))
2999
- if len(dimContainers) > 1:
3000
- modelXbrl.error("xbrlxe:inconsistentDimensionsContainer",
3001
- _("All hypercubes within the DTS of a report MUST be defined for use on the same container (either \"segment\" or \"scenario\")"),
3002
- modelObject=modelXbrl)
3003
- contextsWithNonDimContent = set()
3004
- contextsWithComplexTypedDimensions = set()
3005
- for context in contextsInUse:
3006
- if context.nonDimValues("segment"):
3007
- contextsWithNonDimContent.add(context)
3008
- if context.nonDimValues("scenario"):
3009
- contextsWithNonDimContent.add(context)
3010
- for modelDimension in context.qnameDims.values():
3011
- if modelDimension.isTyped:
3012
- typedMember = modelDimension.typedMember
3013
- if isinstance(typedMember, ModelObject):
3014
- modelConcept = modelXbrl.qnameConcepts.get(typedMember.qname)
3015
- if modelConcept is not None and modelConcept.type is not None and modelConcept.type.localName == "complexType":
3016
- contextsWithComplexTypedDimensions.add(context)
3017
- if contextsWithNonDimContent:
3018
- modelXbrl.error("xbrlxe:nonDimensionalSegmentScenarioContent",
3019
- _("Contexts MUST not contain non-dimensional content: %(contexts)s"),
3020
- modelObject=contextsWithNonDimContent,
3021
- contexts=", ".join(sorted(c.id for c in contextsWithNonDimContent)))
3022
- if contextsWithComplexTypedDimensions:
3023
- modelXbrl.error("xbrlxe:unsupportedComplexTypedDimension", # this pertains only to xBRL-XML validation (JSON and CSV were checked during loading when loadedFromOIM is True)
3024
- _("Instance has contexts with complex typed dimensions: %(contexts)s"),
3025
- modelObject=contextsWithComplexTypedDimensions,
3026
- contexts=", ".join(sorted(c.id for c in contextsWithComplexTypedDimensions)))
3027
-
3028
- footnoteRels = modelXbrl.relationshipSet("XBRL-footnotes")
3029
- # ext group and link roles
3030
- unsupportedExtRoleRefs = defaultdict(list) # role/arcrole and footnote relationship objects referencing it
3031
- footnoteELRs = set()
3032
- footnoteArcroles = set()
3033
- roleDefiningDocs = defaultdict(set)
3034
- def docInSchemaRefedDTS(thisdoc, roleTypeDoc, visited=None):
3035
- if visited is None:
3036
- visited = set()
3037
- visited.add(thisdoc)
3038
- for doc, docRef in thisdoc.referencesDocument.items():
3039
- if thisdoc.type != Type.INSTANCE or docRef.referringModelObject.qname not in nonDiscoveringXmlInstanceElements:
3040
- if doc == roleTypeDoc or (doc not in visited and docInSchemaRefedDTS(doc, roleTypeDoc, visited)):
3041
- return True
3042
- visited.remove(thisdoc)
3043
- return False
3044
- for rel in footnoteRels.modelRelationships:
3045
- if not isStandardRole(rel.linkrole):
3046
- footnoteELRs.add(rel.linkrole)
3047
- if rel.arcrole != factFootnote:
3048
- footnoteArcroles.add(rel.arcrole)
3049
- for elr in footnoteELRs:
3050
- for roleType in modelXbrl.roleTypes[elr]:
3051
- roleDefiningDocs[elr].add(roleType.modelDocument)
3052
- for arcrole in footnoteArcroles:
3053
- for arcroleType in modelXbrl.arcroleTypes[arcrole]:
3054
- roleDefiningDocs[arcrole].add(arcroleType.modelDocument)
3055
- extRoles = set(role
3056
- for role, docs in roleDefiningDocs.items()
3057
- if not any(docInSchemaRefedDTS(modelXbrl.modelDocument, doc) for doc in docs))
3058
- if extRoles:
3059
- modelXbrl.error("xbrlxe:unsupportedExternalRoleRef",
3060
- _("Role and arcrole definitions MUST be in standard or schemaRef discoverable sources"),
3061
- modelObject=modelXbrl, roles=", ".join(sorted(extRoles)))
3062
-
3063
- # todo: multi-document inline instances
3064
- for elt in modelXbrl.modelDocument.xmlRootElement.iter("{http://www.xbrl.org/2003/linkbase}footnote", "{http://www.xbrl.org/2013/inlineXBRL}footnote"):
3065
- if isinstance(elt, ModelResource) and getattr(elt, "xValid", 0) >= VALID:
3066
- if not footnoteRels.toModelObject(elt):
3067
- modelXbrl.error("xbrlxe:unlinkedFootnoteResource",
3068
- _("Unlinked footnote element %(label)s: %(value)s"),
3069
- modelObject=elt, label=elt.xlinkLabel, value=elt.xValue[:100])
3070
- if elt.role not in (None, "", footnote):
3071
- modelXbrl.error("xbrlxe:nonStandardFootnoteResourceRole",
3072
- _("Footnotes MUST have standard footnote resource role, %(role)s is disallowed, %(label)s: %(value)s"),
3073
- modelObject=elt, role=elt.role, label=elt.xlinkLabel, value=elt.xValue[:100])
3074
- # xml base on anything
3075
- for elt in modelXbrl.modelDocument.xmlRootElement.getroottree().iterfind("//{*}*[@{http://www.w3.org/XML/1998/namespace}base]"):
3076
- modelXbrl.error("xbrlxe:unsupportedXmlBase",
3077
- _("Instance MUST NOT contain xml:base attributes: element %(qname)s, xml:base %(base)s"),
3078
- modelObject=elt, qname=elt.qname if isinstance(elt, ModelObject) else elt.tag,
3079
- base=elt.get("{http://www.w3.org/XML/1998/namespace}base"))
3080
- # todo: multi-document inline instances
3081
- if modelXbrl.modelDocument.type in (ModelDocument.Type.INSTANCE, ModelDocument.Type.INLINEXBRL, ModelDocument.Type.INLINEXBRLDOCUMENTSET):
3082
- for doc in modelXbrl.modelDocument.referencesDocument.keys():
3083
- if doc.type == Type.LINKBASE:
3084
- val.modelXbrl.error("xbrlxe:unsupportedLinkbaseReference",
3085
- _("Linkbase reference not allowed from instance document."),
3086
- modelObject=(modelXbrl.modelDocument,doc))
14
+ if not modelXbrl.loadedFromOIM and not modelXbrl.modelManager.validateXmlOim:
15
+ # Consistent legacy behavior. Always perform OIM validation if this plugin is enabled.
16
+ validateOIM(modelXbrl)
3087
17
 
3088
- def excelLoaderOptionExtender(parser, *args, **kwargs):
3089
- parser.add_option("--saveOIMinstance",
3090
- action="store",
3091
- dest="saveOIMinstance",
3092
- help=_("Save a instance loaded from OIM into this file name."))
3093
18
 
3094
19
  __pluginInfo__ = {
3095
- 'name': 'Load From OIM',
3096
- 'version': '1.2',
3097
- 'description': "This plug-in loads XBRL instance data from OIM (JSON, CSV or Excel) and saves the resulting XBRL Instance.",
3098
- 'license': 'Apache-2',
3099
- 'author': authorLabel,
3100
- 'copyright': copyrightLabel,
20
+ "name": "Load From OIM",
21
+ "version": "1.3",
22
+ "description": "(deprecated) this plugin is no longer required. Loading OIM reports no longer requires a plugin.",
23
+ "license": "Apache-2",
24
+ "author": authorLabel,
25
+ "copyright": copyrightLabel,
3101
26
  # classes of mount points (required)
3102
- 'ModelDocument.IsPullLoadable': isOimLoadable,
3103
- 'ModelDocument.PullLoader': oimLoader,
3104
- 'CntlrWinMain.Xbrl.Loaded': guiXbrlLoaded,
3105
- 'CntlrCmdLine.Options': excelLoaderOptionExtender,
3106
- 'CntlrCmdLine.Xbrl.Loaded': cmdLineXbrlLoaded,
3107
- 'Validate.XBRL.Finally': validateFinally
27
+ "Validate.XBRL.Finally": validateFinally,
3108
28
  }