arelle-release 2.37.46__py3-none-any.whl → 2.37.48__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of arelle-release might be problematic. Click here for more details.

Files changed (107) hide show
  1. arelle/CntlrCmdLine.py +10 -1
  2. arelle/ErrorManager.py +14 -5
  3. arelle/ModelObjectFactory.py +18 -2
  4. arelle/Validate.py +4 -0
  5. arelle/_version.py +2 -2
  6. arelle/plugin/validate/DBA/ValidationPluginExtension.py +2 -1
  7. arelle/plugin/validate/EDINET/ControllerPluginData.py +84 -0
  8. arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +0 -114
  9. arelle/plugin/validate/EDINET/UploadContents.py +17 -0
  10. arelle/plugin/validate/EDINET/ValidationPluginExtension.py +8 -2
  11. arelle/plugin/validate/EDINET/__init__.py +5 -0
  12. arelle/plugin/validate/EDINET/rules/upload.py +66 -75
  13. arelle/plugin/validate/NL/ValidationPluginExtension.py +3 -1
  14. arelle/plugin/validate/ROS/ValidationPluginExtension.py +3 -1
  15. arelle/utils/PluginHooks.py +32 -0
  16. arelle/utils/validate/ValidationPlugin.py +54 -8
  17. {arelle_release-2.37.46.dist-info → arelle_release-2.37.48.dist-info}/METADATA +1 -1
  18. {arelle_release-2.37.46.dist-info → arelle_release-2.37.48.dist-info}/RECORD +22 -106
  19. arelle/archive/CustomLogger.py +0 -43
  20. arelle/archive/LoadEFMvalidate.py +0 -32
  21. arelle/archive/LoadSavePreLbCsv.py +0 -26
  22. arelle/archive/LoadValidate.cs +0 -31
  23. arelle/archive/LoadValidate.py +0 -36
  24. arelle/archive/LoadValidateCmdLine.java +0 -69
  25. arelle/archive/LoadValidatePostedZip.java +0 -57
  26. arelle/archive/LoadValidateWebService.java +0 -34
  27. arelle/archive/SaveTableToExelle.py +0 -140
  28. arelle/archive/TR3toTR4.py +0 -88
  29. arelle/archive/plugin/ESEF_2022/__init__.py +0 -47
  30. arelle/archive/plugin/bigInstance.py +0 -394
  31. arelle/archive/plugin/cmdWebServerExtension.py +0 -43
  32. arelle/archive/plugin/crashTest.py +0 -38
  33. arelle/archive/plugin/functionsXmlCreation.py +0 -106
  34. arelle/archive/plugin/hello_i18n.pot +0 -26
  35. arelle/archive/plugin/hello_i18n.py +0 -32
  36. arelle/archive/plugin/importTestChild1.py +0 -21
  37. arelle/archive/plugin/importTestChild2.py +0 -22
  38. arelle/archive/plugin/importTestGrandchild1.py +0 -21
  39. arelle/archive/plugin/importTestGrandchild2.py +0 -21
  40. arelle/archive/plugin/importTestImported1.py +0 -23
  41. arelle/archive/plugin/importTestImported11.py +0 -22
  42. arelle/archive/plugin/importTestParent.py +0 -48
  43. arelle/archive/plugin/instanceInfo.py +0 -306
  44. arelle/archive/plugin/loadFromOIM-2018.py +0 -1282
  45. arelle/archive/plugin/locale/fr/LC_MESSAGES/hello_i18n.po +0 -25
  46. arelle/archive/plugin/objectmaker.py +0 -285
  47. arelle/archive/plugin/packagedImportTest/__init__.py +0 -47
  48. arelle/archive/plugin/packagedImportTest/importTestChild1.py +0 -21
  49. arelle/archive/plugin/packagedImportTest/importTestChild2.py +0 -22
  50. arelle/archive/plugin/packagedImportTest/importTestGrandchild1.py +0 -21
  51. arelle/archive/plugin/packagedImportTest/importTestGrandchild2.py +0 -21
  52. arelle/archive/plugin/packagedImportTest/importTestImported1.py +0 -24
  53. arelle/archive/plugin/packagedImportTest/importTestImported11.py +0 -21
  54. arelle/archive/plugin/packagedImportTest/subdir/importTestImported111.py +0 -21
  55. arelle/archive/plugin/packagedImportTest/subdir/subsubdir/importTestImported1111.py +0 -21
  56. arelle/archive/plugin/sakaCalendar.py +0 -215
  57. arelle/archive/plugin/saveInstanceInfoset.py +0 -121
  58. arelle/archive/plugin/sphinx/FormulaGenerator.py +0 -823
  59. arelle/archive/plugin/sphinx/SphinxContext.py +0 -404
  60. arelle/archive/plugin/sphinx/SphinxEvaluator.py +0 -783
  61. arelle/archive/plugin/sphinx/SphinxMethods.py +0 -1287
  62. arelle/archive/plugin/sphinx/SphinxParser.py +0 -1093
  63. arelle/archive/plugin/sphinx/SphinxValidator.py +0 -163
  64. arelle/archive/plugin/sphinx/US-GAAP Ratios Example.xsr +0 -52
  65. arelle/archive/plugin/sphinx/__init__.py +0 -285
  66. arelle/archive/plugin/streamingExtensions.py +0 -335
  67. arelle/archive/plugin/updateTableLB.py +0 -242
  68. arelle/archive/plugin/validate/SBRnl/CustomLoader.py +0 -19
  69. arelle/archive/plugin/validate/SBRnl/DTS.py +0 -305
  70. arelle/archive/plugin/validate/SBRnl/Dimensions.py +0 -357
  71. arelle/archive/plugin/validate/SBRnl/Document.py +0 -799
  72. arelle/archive/plugin/validate/SBRnl/Filing.py +0 -467
  73. arelle/archive/plugin/validate/SBRnl/__init__.py +0 -75
  74. arelle/archive/plugin/validate/SBRnl/config.xml +0 -26
  75. arelle/archive/plugin/validate/SBRnl/sbr-nl-taxonomies.xml +0 -754
  76. arelle/archive/plugin/validate/USBestPractices.py +0 -570
  77. arelle/archive/plugin/validate/USCorpAction.py +0 -557
  78. arelle/archive/plugin/validate/USSecTagging.py +0 -337
  79. arelle/archive/plugin/validate/XDC/__init__.py +0 -77
  80. arelle/archive/plugin/validate/XDC/config.xml +0 -20
  81. arelle/archive/plugin/validate/XFsyntax/__init__.py +0 -64
  82. arelle/archive/plugin/validate/XFsyntax/xf.py +0 -2227
  83. arelle/archive/plugin/validate/calc2.py +0 -536
  84. arelle/archive/plugin/validateSchemaLxml.py +0 -156
  85. arelle/archive/plugin/validateTableInfoset.py +0 -52
  86. arelle/archive/us-gaap-dei-docType-extraction-frm.xml +0 -90
  87. arelle/archive/us-gaap-dei-ratio-cash-frm.xml +0 -150
  88. arelle/examples/plugin/formulaSuiteConverter.py +0 -212
  89. arelle/examples/plugin/functionsCustom.py +0 -59
  90. arelle/examples/plugin/hello_dolly.py +0 -64
  91. arelle/examples/plugin/multi.py +0 -58
  92. arelle/examples/plugin/rssSaveOim.py +0 -96
  93. arelle/examples/plugin/validate/XYZ/DisclosureSystems.py +0 -2
  94. arelle/examples/plugin/validate/XYZ/PluginValidationDataExtension.py +0 -10
  95. arelle/examples/plugin/validate/XYZ/ValidationPluginExtension.py +0 -49
  96. arelle/examples/plugin/validate/XYZ/__init__.py +0 -75
  97. arelle/examples/plugin/validate/XYZ/resources/config.xml +0 -16
  98. arelle/examples/plugin/validate/XYZ/rules/__init__.py +0 -0
  99. arelle/examples/plugin/validate/XYZ/rules/rules01.py +0 -110
  100. arelle/examples/plugin/validate/XYZ/rules/rules02.py +0 -59
  101. arelle/scripts-macOS/startWebServer.command +0 -3
  102. arelle/scripts-unix/startWebServer.sh +0 -1
  103. arelle/scripts-windows/startWebServer.bat +0 -5
  104. {arelle_release-2.37.46.dist-info → arelle_release-2.37.48.dist-info}/WHEEL +0 -0
  105. {arelle_release-2.37.46.dist-info → arelle_release-2.37.48.dist-info}/entry_points.txt +0 -0
  106. {arelle_release-2.37.46.dist-info → arelle_release-2.37.48.dist-info}/licenses/LICENSE.md +0 -0
  107. {arelle_release-2.37.46.dist-info → arelle_release-2.37.48.dist-info}/top_level.txt +0 -0
@@ -6,8 +6,10 @@ from __future__ import annotations
6
6
  import re
7
7
  from collections import defaultdict
8
8
  from pathlib import Path
9
- from typing import Any, Iterable
9
+ from typing import Any, Iterable, TYPE_CHECKING
10
10
 
11
+ from arelle.Cntlr import Cntlr
12
+ from arelle.FileSource import FileSource
11
13
  from arelle.ValidateXbrl import ValidateXbrl
12
14
  from arelle.typing import TypeGetText
13
15
  from arelle.utils.PluginHooks import ValidationHook
@@ -17,6 +19,9 @@ from ..DisclosureSystems import (DISCLOSURE_SYSTEM_EDINET)
17
19
  from ..InstanceType import InstanceType, HTML_EXTENSIONS, IMAGE_EXTENSIONS
18
20
  from ..PluginValidationDataExtension import PluginValidationDataExtension
19
21
 
22
+ if TYPE_CHECKING:
23
+ from ..ControllerPluginData import ControllerPluginData
24
+
20
25
  _: TypeGetText
21
26
 
22
27
  FILE_COUNT_LIMITS = {
@@ -35,12 +40,13 @@ FILENAME_STEM_PATTERN = re.compile(r'[a-zA-Z0-9_-]*')
35
40
 
36
41
 
37
42
  @validation(
38
- hook=ValidationHook.XBRL_FINALLY,
43
+ hook=ValidationHook.FILESOURCE,
39
44
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
40
45
  )
41
46
  def rule_EC0121E(
42
- pluginData: PluginValidationDataExtension,
43
- val: ValidateXbrl,
47
+ pluginData: ControllerPluginData,
48
+ cntlr: Cntlr,
49
+ fileSource: FileSource,
44
50
  *args: Any,
45
51
  **kwargs: Any,
46
52
  ) -> Iterable[Validation]:
@@ -53,9 +59,7 @@ def rule_EC0121E(
53
59
  i.e. amendment documents. For now, we will only check amendment documents, directory
54
60
  names, or other files in unexpected locations.
55
61
  """
56
- if not pluginData.shouldValidateUpload(val):
57
- return
58
- uploadContents = pluginData.getUploadContents(val.modelXbrl)
62
+ uploadContents = pluginData.getUploadContents(fileSource)
59
63
  paths = set(uploadContents.directories | uploadContents.unknownPaths)
60
64
  for amendmentPaths in uploadContents.amendmentPaths.values():
61
65
  paths.update(amendmentPaths)
@@ -75,21 +79,20 @@ def rule_EC0121E(
75
79
 
76
80
 
77
81
  @validation(
78
- hook=ValidationHook.XBRL_FINALLY,
82
+ hook=ValidationHook.FILESOURCE,
79
83
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
80
84
  )
81
85
  def rule_EC0124E(
82
- pluginData: PluginValidationDataExtension,
83
- val: ValidateXbrl,
86
+ pluginData: ControllerPluginData,
87
+ cntlr: Cntlr,
88
+ fileSource: FileSource,
84
89
  *args: Any,
85
90
  **kwargs: Any,
86
91
  ) -> Iterable[Validation]:
87
92
  """
88
93
  EDINET.EC0124E: There are no empty directories.
89
94
  """
90
- if not pluginData.shouldValidateUpload(val):
91
- return
92
- uploadFilepaths = pluginData.getUploadFilepaths(val.modelXbrl)
95
+ uploadFilepaths = pluginData.getUploadFilepaths(fileSource)
93
96
  emptyDirectories = []
94
97
  for path in uploadFilepaths:
95
98
  if path.suffix:
@@ -107,12 +110,13 @@ def rule_EC0124E(
107
110
 
108
111
 
109
112
  @validation(
110
- hook=ValidationHook.XBRL_FINALLY,
113
+ hook=ValidationHook.FILESOURCE,
111
114
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
112
115
  )
113
116
  def rule_EC0129E(
114
- pluginData: PluginValidationDataExtension,
115
- val: ValidateXbrl,
117
+ pluginData: ControllerPluginData,
118
+ cntlr: Cntlr,
119
+ fileSource: FileSource,
116
120
  *args: Any,
117
121
  **kwargs: Any,
118
122
  ) -> Iterable[Validation]:
@@ -120,9 +124,7 @@ def rule_EC0129E(
120
124
  EDINET.EC0129E: Limit the number of subfolders to 3 or less from the XBRL directory.
121
125
  """
122
126
  startingDirectory = 'XBRL'
123
- if not pluginData.shouldValidateUpload(val):
124
- return
125
- uploadFilepaths = pluginData.getUploadFilepaths(val.modelXbrl)
127
+ uploadFilepaths = pluginData.getUploadFilepaths(fileSource)
126
128
  for path in uploadFilepaths:
127
129
  parents = [parent.name for parent in path.parents]
128
130
  if startingDirectory in parents:
@@ -144,21 +146,20 @@ def rule_EC0129E(
144
146
 
145
147
 
146
148
  @validation(
147
- hook=ValidationHook.XBRL_FINALLY,
149
+ hook=ValidationHook.FILESOURCE,
148
150
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
149
151
  )
150
152
  def rule_EC0130E(
151
- pluginData: PluginValidationDataExtension,
152
- val: ValidateXbrl,
153
+ pluginData: ControllerPluginData,
154
+ cntlr: Cntlr,
155
+ fileSource: FileSource,
153
156
  *args: Any,
154
157
  **kwargs: Any,
155
158
  ) -> Iterable[Validation]:
156
159
  """
157
160
  EDINET.EC0130E: File extensions must match the file extensions allowed in Figure 2-1-3 and Figure 2-1-5.
158
161
  """
159
- if not pluginData.shouldValidateUpload(val):
160
- return
161
- uploadContents = pluginData.getUploadContents(val.modelXbrl)
162
+ uploadContents = pluginData.getUploadContents(fileSource)
162
163
  checks = []
163
164
  for instanceType, amendmentPaths in uploadContents.amendmentPaths.items():
164
165
  for amendmentPath in amendmentPaths:
@@ -192,21 +193,20 @@ def rule_EC0130E(
192
193
 
193
194
 
194
195
  @validation(
195
- hook=ValidationHook.XBRL_FINALLY,
196
+ hook=ValidationHook.FILESOURCE,
196
197
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
197
198
  )
198
199
  def rule_EC0132E(
199
- pluginData: PluginValidationDataExtension,
200
- val: ValidateXbrl,
200
+ pluginData: ControllerPluginData,
201
+ cntlr: Cntlr,
202
+ fileSource: FileSource,
201
203
  *args: Any,
202
204
  **kwargs: Any,
203
205
  ) -> Iterable[Validation]:
204
206
  """
205
207
  EDINET.EC0132E: Store the manifest file directly under the relevant folder.
206
208
  """
207
- if not pluginData.shouldValidateUpload(val):
208
- return
209
- uploadContents = pluginData.getUploadContents(val.modelXbrl)
209
+ uploadContents = pluginData.getUploadContents(fileSource)
210
210
  for instanceType in (InstanceType.AUDIT_DOC, InstanceType.PRIVATE_DOC, InstanceType.PUBLIC_DOC):
211
211
  if instanceType not in uploadContents.instances:
212
212
  continue
@@ -222,21 +222,20 @@ def rule_EC0132E(
222
222
 
223
223
 
224
224
  @validation(
225
- hook=ValidationHook.XBRL_FINALLY,
225
+ hook=ValidationHook.FILESOURCE,
226
226
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
227
227
  )
228
228
  def rule_EC0183E(
229
- pluginData: PluginValidationDataExtension,
230
- val: ValidateXbrl,
229
+ pluginData: ControllerPluginData,
230
+ cntlr: Cntlr,
231
+ fileSource: FileSource,
231
232
  *args: Any,
232
233
  **kwargs: Any,
233
234
  ) -> Iterable[Validation]:
234
235
  """
235
236
  EDINET.EC0183E: The compressed file size exceeds 55MB.
236
237
  """
237
- if not pluginData.shouldValidateUpload(val):
238
- return
239
- size = val.modelXbrl.fileSource.getBytesSize()
238
+ size = fileSource.getBytesSize()
240
239
  if size is None:
241
240
  return # File size is not available, cannot validate
242
241
  if size > 55_000_000: # Interpretting MB as megabytes (1,000,000 bytes)
@@ -248,22 +247,21 @@ def rule_EC0183E(
248
247
 
249
248
 
250
249
  @validation(
251
- hook=ValidationHook.XBRL_FINALLY,
250
+ hook=ValidationHook.FILESOURCE,
252
251
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
253
252
  )
254
253
  def rule_EC0188E(
255
- pluginData: PluginValidationDataExtension,
256
- val: ValidateXbrl,
254
+ pluginData: ControllerPluginData,
255
+ cntlr: Cntlr,
256
+ fileSource: FileSource,
257
257
  *args: Any,
258
258
  **kwargs: Any,
259
259
  ) -> Iterable[Validation]:
260
260
  """
261
261
  EDINET.EC0188E: There is an HTML file directly under PublicDoc or PrivateDoc whose first 7 characters are not numbers.
262
262
  """
263
- if not pluginData.shouldValidateUpload(val):
264
- return
265
263
  pattern = re.compile(r'^\d{7}')
266
- uploadFilepaths = pluginData.getUploadFilepaths(val.modelXbrl)
264
+ uploadFilepaths = pluginData.getUploadFilepaths(fileSource)
267
265
  docFolders = frozenset({"PublicDoc", "PrivateDoc"})
268
266
  for path in uploadFilepaths:
269
267
  if path.suffix not in HTML_EXTENSIONS:
@@ -282,22 +280,21 @@ def rule_EC0188E(
282
280
 
283
281
 
284
282
  @validation(
285
- hook=ValidationHook.XBRL_FINALLY,
283
+ hook=ValidationHook.FILESOURCE,
286
284
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
287
285
  )
288
286
  def rule_EC0198E(
289
- pluginData: PluginValidationDataExtension,
290
- val: ValidateXbrl,
287
+ pluginData: ControllerPluginData,
288
+ cntlr: Cntlr,
289
+ fileSource: FileSource,
291
290
  *args: Any,
292
291
  **kwargs: Any,
293
292
  ) -> Iterable[Validation]:
294
293
  """
295
294
  EDINET.EC0198E: The number of files in the total submission and directories can not exceed the upper limit.
296
295
  """
297
- if not pluginData.shouldValidateUpload(val):
298
- return
299
296
  fileCounts: dict[Path, int] = defaultdict(int)
300
- uploadFilepaths = pluginData.getUploadFilepaths(val.modelXbrl)
297
+ uploadFilepaths = pluginData.getUploadFilepaths(fileSource)
301
298
  for path in uploadFilepaths:
302
299
  if len(path.suffix) == 0:
303
300
  continue
@@ -319,21 +316,20 @@ def rule_EC0198E(
319
316
 
320
317
 
321
318
  @validation(
322
- hook=ValidationHook.XBRL_FINALLY,
319
+ hook=ValidationHook.FILESOURCE,
323
320
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
324
321
  )
325
322
  def rule_EC0237E(
326
- pluginData: PluginValidationDataExtension,
327
- val: ValidateXbrl,
323
+ pluginData: ControllerPluginData,
324
+ cntlr: Cntlr,
325
+ fileSource: FileSource,
328
326
  *args: Any,
329
327
  **kwargs: Any,
330
328
  ) -> Iterable[Validation]:
331
329
  """
332
330
  EDINET.EC0237E: The directory or file path to the lowest level exceeds the maximum value (259 characters).
333
331
  """
334
- if not pluginData.shouldValidateUpload(val):
335
- return
336
- uploadFilepaths = pluginData.getUploadFilepaths(val.modelXbrl)
332
+ uploadFilepaths = pluginData.getUploadFilepaths(fileSource)
337
333
  for path in uploadFilepaths:
338
334
  if len(str(path)) <= 259:
339
335
  continue
@@ -348,21 +344,20 @@ def rule_EC0237E(
348
344
 
349
345
 
350
346
  @validation(
351
- hook=ValidationHook.XBRL_FINALLY,
347
+ hook=ValidationHook.FILESOURCE,
352
348
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
353
349
  )
354
350
  def rule_EC0206E(
355
- pluginData: PluginValidationDataExtension,
356
- val: ValidateXbrl,
351
+ pluginData: ControllerPluginData,
352
+ cntlr: Cntlr,
353
+ fileSource: FileSource,
357
354
  *args: Any,
358
355
  **kwargs: Any,
359
356
  ) -> Iterable[Validation]:
360
357
  """
361
358
  EDINET.EC0206E: Empty files are not permitted.
362
359
  """
363
- if not pluginData.shouldValidateUpload(val):
364
- return
365
- for path, size in pluginData.getUploadFileSizes(val.modelXbrl).items():
360
+ for path, size in pluginData.getUploadFileSizes(fileSource).items():
366
361
  if size > 0:
367
362
  continue
368
363
  yield Validation.error(
@@ -376,21 +371,20 @@ def rule_EC0206E(
376
371
 
377
372
 
378
373
  @validation(
379
- hook=ValidationHook.XBRL_FINALLY,
374
+ hook=ValidationHook.FILESOURCE,
380
375
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
381
376
  )
382
377
  def rule_EC1016E(
383
- pluginData: PluginValidationDataExtension,
384
- val: ValidateXbrl,
378
+ pluginData: ControllerPluginData,
379
+ cntlr: Cntlr,
380
+ fileSource: FileSource,
385
381
  *args: Any,
386
382
  **kwargs: Any,
387
383
  ) -> Iterable[Validation]:
388
384
  """
389
385
  EDINET.EC1016E: The image file is over 300KB.
390
386
  """
391
- if not pluginData.shouldValidateUpload(val):
392
- return
393
- for path, size in pluginData.getUploadFileSizes(val.modelXbrl).items():
387
+ for path, size in pluginData.getUploadFileSizes(fileSource).items():
394
388
  if path.suffix not in IMAGE_EXTENSIONS:
395
389
  continue
396
390
  if size <= 300_000: # Interpretting KB as kilobytes (1,000 bytes)
@@ -422,8 +416,6 @@ def rule_EC1020E(
422
416
  Note: Some violations of this rule (such as multiple DOCTYPE declarations) prevent Arelle from parsing
423
417
  the XML at all, and thus an XML schema error will be triggered rather than this validation error.
424
418
  """
425
- if not pluginData.shouldValidateUpload(val):
426
- return
427
419
  checkNames = frozenset({'body', 'head', 'html'})
428
420
  for modelDocument in val.modelXbrl.urlDocs.values():
429
421
  path = Path(modelDocument.uri)
@@ -453,12 +445,13 @@ def rule_EC1020E(
453
445
 
454
446
 
455
447
  @validation(
456
- hook=ValidationHook.XBRL_FINALLY,
448
+ hook=ValidationHook.FILESOURCE,
457
449
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
458
450
  )
459
451
  def rule_manifest_preferredFilename(
460
- pluginData: PluginValidationDataExtension,
461
- val: ValidateXbrl,
452
+ pluginData: ControllerPluginData,
453
+ cntlr: Cntlr,
454
+ fileSource: FileSource,
462
455
  *args: Any,
463
456
  **kwargs: Any,
464
457
  ) -> Iterable[Validation]:
@@ -474,9 +467,7 @@ def rule_manifest_preferredFilename(
474
467
  The preferredFilename attribute value of the instance element in the manifest
475
468
  file must be unique within the same file.
476
469
  """
477
- if not pluginData.shouldValidateUpload(val):
478
- return
479
- instances = pluginData.getManifestInstances(val.modelXbrl)
470
+ instances = pluginData.getManifestInstances()
480
471
  preferredFilenames: dict[Path, set[str]] = defaultdict(set)
481
472
  duplicateFilenames = defaultdict(set)
482
473
  for instance in instances:
@@ -4,6 +4,7 @@ See COPYRIGHT.md for copyright information.
4
4
  from __future__ import annotations
5
5
  from typing import Any
6
6
 
7
+ from arelle.Cntlr import Cntlr
7
8
  from arelle.ModelDocument import LoadingException, ModelDocument
8
9
  from arelle.ModelValue import qname
9
10
  from arelle.ModelXbrl import ModelXbrl
@@ -19,7 +20,8 @@ _: TypeGetText
19
20
 
20
21
 
21
22
  class ValidationPluginExtension(ValidationPlugin):
22
- def newPluginData(self, validateXbrl: ValidateXbrl) -> PluginValidationDataExtension:
23
+ def newPluginData(self, cntlr: Cntlr, validateXbrl: ValidateXbrl | None) -> PluginValidationDataExtension:
24
+ assert validateXbrl is not None
23
25
  disclosureSystem = validateXbrl.disclosureSystem.name
24
26
  if disclosureSystem == DISCLOSURE_SYSTEM_NT16:
25
27
  ifrsNamespace = None
@@ -2,6 +2,8 @@
2
2
  See COPYRIGHT.md for copyright information.
3
3
  """
4
4
  from __future__ import annotations
5
+
6
+ from arelle.Cntlr import Cntlr
5
7
  from arelle.ValidateXbrl import ValidateXbrl
6
8
  from arelle.typing import TypeGetText
7
9
  from arelle.utils.validate.ValidationPlugin import ValidationPlugin
@@ -18,7 +20,7 @@ TURNOVER_REVENUE = 'DPLTurnoverRevenue'
18
20
 
19
21
 
20
22
  class ValidationPluginExtension(ValidationPlugin):
21
- def newPluginData(self, validateXbrl: ValidateXbrl) -> PluginValidationDataExtension:
23
+ def newPluginData(self, cntlr: Cntlr, validateXbrl: ValidateXbrl | None) -> PluginValidationDataExtension:
22
24
  return PluginValidationDataExtension(
23
25
  self.name
24
26
  )
@@ -34,6 +34,7 @@ class ValidationHook(Enum):
34
34
  These hooks are called at different stages of validation, but all provide a common interface (ValidateXbrl is the first param).
35
35
  """
36
36
 
37
+ FILESOURCE = "Validate.FileSource"
37
38
  XBRL_START = "Validate.XBRL.Start"
38
39
  XBRL_FINALLY = "Validate.XBRL.Finally"
39
40
  XBRL_DTS_DOCUMENT = "Validate.XBRL.DTS.document"
@@ -568,6 +569,37 @@ class PluginHooks(ABC):
568
569
  """
569
570
  raise NotImplementedError
570
571
 
572
+ @staticmethod
573
+ def validateFileSource(
574
+ cntlr: Cntlr,
575
+ fileSource: FileSource,
576
+ entrypoints: list[dict[str, Any]] | None = None,
577
+ *args: Any,
578
+ **kwargs: Any,
579
+ ) -> None:
580
+ """
581
+ Plugin hook: `Validate.FileSource`
582
+
583
+ Hook for executing validation rules applicable to entrypoint files.
584
+
585
+ Example:
586
+ ```python
587
+ size = fileSource.getBytesSize()
588
+ if size is None:
589
+ return
590
+ if size > 100_000_000:
591
+ yield Validation.error(codes="0.0.0", msg="File size exceeds 100MB.")
592
+ ```
593
+
594
+ :param cntlr: The [Cntlr](#arelle.Cntlr.Cntlr) instance.
595
+ :param fileSource: The [FileSource](#arelle.FileSource.FileSource) involved in loading the entrypoint files.
596
+ :param entrypoints: A list of entrypoint configurations.
597
+ :param args: Argument capture to ensure new parameters don't break plugin hook.
598
+ :param kwargs: Argument capture to ensure new named parameters don't break plugin hook.
599
+ :return: None
600
+ """
601
+ raise NotImplementedError
602
+
571
603
  @staticmethod
572
604
  def validateFinally(
573
605
  val: ValidateXbrl,
@@ -8,17 +8,19 @@ from pathlib import Path
8
8
  from types import ModuleType
9
9
  from typing import Any
10
10
 
11
+ from arelle.Cntlr import Cntlr
11
12
  from arelle.DisclosureSystem import DisclosureSystem
13
+ from arelle.FileSource import FileSource
12
14
  from arelle.ModelDocument import LoadingException, ModelDocument
13
15
  from arelle.ModelXbrl import ModelXbrl
14
16
  from arelle.ValidateXbrl import ValidateXbrl
17
+ from arelle.utils.PluginData import PluginData
15
18
  from arelle.utils.PluginHooks import ValidationHook
16
19
  from arelle.utils.validate.Decorator import (
17
20
  ValidationAttributes,
18
21
  ValidationFunction,
19
22
  getValidationAttributes,
20
23
  )
21
- from arelle.utils.PluginData import PluginData
22
24
 
23
25
 
24
26
  class ValidationPlugin:
@@ -55,7 +57,7 @@ class ValidationPlugin:
55
57
  ValidationHook, dict[ValidationFunction, set[str]]
56
58
  ] = {}
57
59
 
58
- def newPluginData(self, validateXbrl: ValidateXbrl) -> PluginData:
60
+ def newPluginData(self, cntlr: Cntlr, validateXbrl: ValidateXbrl | None) -> PluginData:
59
61
  """
60
62
  Returns a dataclass intended to be overriden by plugins to facilitate caching and passing data between rule functions.
61
63
  The default implementation doesn't provide any fields other than the plugin name.
@@ -99,6 +101,28 @@ class ValidationPlugin:
99
101
  ) -> ModelDocument | LoadingException | None:
100
102
  raise NotImplementedError
101
103
 
104
+ def validateFileSource(
105
+ self,
106
+ cntlr: Cntlr,
107
+ fileSource: FileSource,
108
+ entrypoints: list[dict[str, Any]] | None = None,
109
+ *args: Any,
110
+ **kwargs: Any,
111
+ ) -> None:
112
+ """
113
+ Executes validation functions in the rules module that was provided to the constructor of this class.
114
+ Each function decorated with [@validation](#arelle.utils.validate.Decorator.validation) will be run if:
115
+ 1. the decorator was used with the xbrl start hook: `@validation(hook=ValidationHook.FILESOURCE)`
116
+
117
+ :param cntlr: The [Cntlr](#arelle.Cntlr.Cntlr) instance.
118
+ :param fileSource: The [FileSource](#arelle.FileSource.FileSource) involved in loading the entrypoint files.
119
+ :param entrypoints: A list of entrypoint configurations.
120
+ :param args: Argument capture to ensure new parameters don't break plugin hook.
121
+ :param kwargs: Argument capture to ensure new named parameters don't break plugin hook.
122
+ :return: None
123
+ """
124
+ self._executeCntlrValidations(ValidationHook.FILESOURCE, cntlr, fileSource, entrypoints, *args, **kwargs)
125
+
102
126
  def validateXbrlStart(
103
127
  self,
104
128
  val: ValidateXbrl,
@@ -118,7 +142,7 @@ class ValidationPlugin:
118
142
  :param kwargs: Argument capture to ensure new named parameters don't break plugin hook.
119
143
  :return: None
120
144
  """
121
- self._executeValidations(ValidationHook.XBRL_START, val, parameters, *args, **kwargs)
145
+ self._executeModelValidations(ValidationHook.XBRL_START, val, parameters, *args, **kwargs)
122
146
 
123
147
  def validateXbrlFinally(
124
148
  self,
@@ -137,7 +161,7 @@ class ValidationPlugin:
137
161
  :param kwargs: Argument capture to ensure new named parameters don't break plugin hook.
138
162
  :return: None
139
163
  """
140
- self._executeValidations(ValidationHook.XBRL_FINALLY, val, *args, **kwargs)
164
+ self._executeModelValidations(ValidationHook.XBRL_FINALLY, val, *args, **kwargs)
141
165
 
142
166
  def validateXbrlDtsDocument(
143
167
  self,
@@ -158,7 +182,7 @@ class ValidationPlugin:
158
182
  :param kwargs: Argument capture to ensure new named parameters don't break plugin hook.
159
183
  :return: None
160
184
  """
161
- self._executeValidations(ValidationHook.XBRL_DTS_DOCUMENT, val, modelDocument, isFilingDocument, *args, **kwargs)
185
+ self._executeModelValidations(ValidationHook.XBRL_DTS_DOCUMENT, val, modelDocument, isFilingDocument, *args, **kwargs)
162
186
 
163
187
  def validateFinally(
164
188
  self,
@@ -177,9 +201,28 @@ class ValidationPlugin:
177
201
  :param kwargs: Argument capture to ensure new named parameters don't break plugin hook.
178
202
  :return: None
179
203
  """
180
- self._executeValidations(ValidationHook.FINALLY, val, *args, **kwargs)
204
+ self._executeModelValidations(ValidationHook.FINALLY, val, *args, **kwargs)
205
+
206
+ def _executeCntlrValidations(
207
+ self,
208
+ pluginHook: ValidationHook,
209
+ cntlr: Cntlr,
210
+ fileSource: FileSource | None = None,
211
+ entrypoints: list[dict[str, Any]] | None = None,
212
+ *args: Any,
213
+ **kwargs: Any,
214
+ ) -> None:
215
+ pluginData = self.newPluginData(
216
+ cntlr=cntlr,
217
+ validateXbrl=None
218
+ )
219
+ for rule in self._getValidations(cntlr.modelManager.disclosureSystem, pluginHook):
220
+ validations = rule(pluginData, cntlr, fileSource, entrypoints, *args, **kwargs)
221
+ if validations is not None:
222
+ for val in validations:
223
+ cntlr.error(level=val.level.name, codes=val.codes, msg=val.msg, **val.args)
181
224
 
182
- def _executeValidations(
225
+ def _executeModelValidations(
183
226
  self,
184
227
  pluginHook: ValidationHook,
185
228
  validateXbrl: ValidateXbrl,
@@ -189,7 +232,10 @@ class ValidationPlugin:
189
232
  if self.disclosureSystemFromPluginSelected(validateXbrl):
190
233
  pluginData = validateXbrl.getPluginData(self.name)
191
234
  if pluginData is None:
192
- pluginData = self.newPluginData(validateXbrl)
235
+ pluginData = self.newPluginData(
236
+ cntlr=validateXbrl.modelXbrl.modelManager.cntlr,
237
+ validateXbrl=validateXbrl
238
+ )
193
239
  validateXbrl.setPluginData(pluginData)
194
240
  for rule in self._getValidations(validateXbrl.disclosureSystem, pluginHook):
195
241
  validations = rule(pluginData, validateXbrl, *args, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arelle-release
3
- Version: 2.37.46
3
+ Version: 2.37.48
4
4
  Summary: An open source XBRL platform.
5
5
  Author-email: "arelle.org" <support@arelle.org>
6
6
  License-Expression: Apache-2.0