arelle-release 2.37.57__py3-none-any.whl → 2.37.58__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.
- arelle/Cntlr.py +1 -0
- arelle/DialogPluginManager.py +6 -4
- arelle/ErrorManager.py +4 -1
- arelle/PluginManager.py +129 -100
- arelle/_version.py +2 -2
- arelle/plugin/validate/EDINET/Constants.py +19 -0
- arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +31 -0
- arelle/plugin/validate/EDINET/rules/gfm.py +84 -0
- {arelle_release-2.37.57.dist-info → arelle_release-2.37.58.dist-info}/METADATA +1 -1
- {arelle_release-2.37.57.dist-info → arelle_release-2.37.58.dist-info}/RECORD +14 -14
- {arelle_release-2.37.57.dist-info → arelle_release-2.37.58.dist-info}/WHEEL +0 -0
- {arelle_release-2.37.57.dist-info → arelle_release-2.37.58.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.37.57.dist-info → arelle_release-2.37.58.dist-info}/licenses/LICENSE.md +0 -0
- {arelle_release-2.37.57.dist-info → arelle_release-2.37.58.dist-info}/top_level.txt +0 -0
arelle/Cntlr.py
CHANGED
arelle/DialogPluginManager.py
CHANGED
|
@@ -386,15 +386,17 @@ class DialogPluginManager(Toplevel):
|
|
|
386
386
|
group = {
|
|
387
387
|
"ixbrl-viewer": "1", # pip installed Arelle viewer
|
|
388
388
|
"iXBRLViewerPlugin": "2", # git clone installed Arelle viewer
|
|
389
|
-
"
|
|
389
|
+
"EDGAR": "3",
|
|
390
|
+
"Inline XBRL Document Set": "4",
|
|
391
|
+
"XBRL rule processor (xule)": "5",
|
|
390
392
|
}.get(key)
|
|
391
393
|
if not group:
|
|
392
394
|
if key.startswith("Validate"):
|
|
393
|
-
group = "
|
|
395
|
+
group = "6"
|
|
394
396
|
elif key.startswith("xbrlDB"):
|
|
395
|
-
group = "
|
|
397
|
+
group = "7"
|
|
396
398
|
else:
|
|
397
|
-
group = "
|
|
399
|
+
group = "8"
|
|
398
400
|
return group + key.lower()
|
|
399
401
|
|
|
400
402
|
@staticmethod
|
arelle/ErrorManager.py
CHANGED
|
@@ -180,7 +180,10 @@ class ErrorManager:
|
|
|
180
180
|
objectUrl = arg
|
|
181
181
|
else:
|
|
182
182
|
try:
|
|
183
|
-
|
|
183
|
+
if isinstance(arg, ObjectPropertyViewWrapper):
|
|
184
|
+
objectUrl = arg.modelObject.modelDocument.displayUri
|
|
185
|
+
else:
|
|
186
|
+
objectUrl = arg.modelDocument.displayUri
|
|
184
187
|
except AttributeError:
|
|
185
188
|
try:
|
|
186
189
|
objectUrl = arg.displayUri
|
arelle/PluginManager.py
CHANGED
|
@@ -1,31 +1,41 @@
|
|
|
1
1
|
'''
|
|
2
2
|
See COPYRIGHT.md for copyright information.
|
|
3
|
-
|
|
4
|
-
based on pull request 4
|
|
5
|
-
|
|
6
3
|
'''
|
|
7
4
|
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
|
|
6
|
+
import ast
|
|
7
|
+
import gettext
|
|
8
|
+
from glob import glob
|
|
11
9
|
import importlib.util
|
|
10
|
+
import json
|
|
12
11
|
import logging
|
|
13
|
-
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
import time
|
|
15
|
+
import traceback
|
|
16
|
+
import types
|
|
17
|
+
from collections import defaultdict
|
|
18
|
+
from collections.abc import Callable, Iterator
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from importlib.metadata import EntryPoint, entry_points
|
|
21
|
+
from numbers import Number
|
|
22
|
+
from pathlib import Path
|
|
14
23
|
from types import ModuleType
|
|
15
24
|
from typing import TYPE_CHECKING, Any, cast
|
|
16
|
-
|
|
25
|
+
|
|
17
26
|
import arelle.FileSource
|
|
27
|
+
from arelle.Locale import getLanguageCodes
|
|
18
28
|
from arelle.PythonUtil import isLegacyAbs
|
|
29
|
+
from arelle.typing import TypeGetText
|
|
19
30
|
from arelle.UrlUtil import isAbsolute
|
|
20
|
-
from pathlib import Path
|
|
21
|
-
from collections import OrderedDict, defaultdict
|
|
22
|
-
from collections.abc import Callable, Iterator
|
|
23
|
-
|
|
24
31
|
|
|
25
32
|
if TYPE_CHECKING:
|
|
26
33
|
# Prevent potential circular import error
|
|
27
34
|
from .Cntlr import Cntlr
|
|
28
35
|
|
|
36
|
+
|
|
37
|
+
_: TypeGetText
|
|
38
|
+
|
|
29
39
|
PLUGIN_TRACE_FILE = None
|
|
30
40
|
# PLUGIN_TRACE_FILE = "c:/temp/pluginerr.txt"
|
|
31
41
|
PLUGIN_TRACE_LEVEL = logging.WARNING
|
|
@@ -58,7 +68,7 @@ def init(cntlr: Cntlr, loadPluginConfig: bool = True) -> None:
|
|
|
58
68
|
if loadPluginConfig:
|
|
59
69
|
try:
|
|
60
70
|
pluginJsonFile = cntlr.userAppDir + os.sep + "plugins.json"
|
|
61
|
-
with
|
|
71
|
+
with open(pluginJsonFile, encoding='utf-8') as f:
|
|
62
72
|
pluginConfig = json.load(f)
|
|
63
73
|
freshenModuleInfos()
|
|
64
74
|
except Exception:
|
|
@@ -79,29 +89,45 @@ def reset() -> None: # force reloading modules and plugin infos
|
|
|
79
89
|
pluginMethodsForClasses.clear() # dict by class of list of ordered callable function objects
|
|
80
90
|
|
|
81
91
|
def orderedPluginConfig():
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
92
|
+
fieldOrder = [
|
|
93
|
+
'name',
|
|
94
|
+
'status',
|
|
95
|
+
'fileDate',
|
|
96
|
+
'version',
|
|
97
|
+
'description',
|
|
98
|
+
'moduleURL',
|
|
99
|
+
'localeURL',
|
|
100
|
+
'localeDomain',
|
|
101
|
+
'license',
|
|
102
|
+
'author',
|
|
103
|
+
'copyright',
|
|
104
|
+
'classMethods',
|
|
105
|
+
]
|
|
106
|
+
priorityIndex = {k: i for i, k in enumerate(fieldOrder)}
|
|
107
|
+
|
|
108
|
+
def sortModuleInfo(moduleInfo):
|
|
109
|
+
# Prioritize known fields by the index in fieldOrder; sort others alphabetically
|
|
110
|
+
orderedKeys = sorted(
|
|
111
|
+
moduleInfo.keys(),
|
|
112
|
+
key=lambda k: (priorityIndex.get(k, len(priorityIndex)), k)
|
|
113
|
+
)
|
|
114
|
+
return {k: moduleInfo[k] for k in orderedKeys}
|
|
115
|
+
|
|
116
|
+
orderedModules = {
|
|
117
|
+
moduleName: sortModuleInfo(pluginConfig['modules'][moduleName])
|
|
118
|
+
for moduleName in sorted(pluginConfig['modules'].keys())
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
'modules': orderedModules,
|
|
123
|
+
'classes': dict(sorted(pluginConfig['classes'].items()))
|
|
124
|
+
}
|
|
99
125
|
|
|
100
126
|
def save(cntlr: Cntlr) -> None:
|
|
101
127
|
global pluginConfigChanged
|
|
102
128
|
if pluginConfigChanged and cntlr.hasFileSystem and not cntlr.disablePersistentConfig:
|
|
103
129
|
pluginJsonFile = cntlr.userAppDir + os.sep + "plugins.json"
|
|
104
|
-
with
|
|
130
|
+
with open(pluginJsonFile, 'w', encoding='utf-8') as f:
|
|
105
131
|
jsonStr = str(json.dumps(orderedPluginConfig(), ensure_ascii=False, indent=2)) # might not be unicode in 2.7
|
|
106
132
|
f.write(jsonStr)
|
|
107
133
|
pluginConfigChanged = False
|
|
@@ -155,7 +181,6 @@ moduleInfo = {
|
|
|
155
181
|
|
|
156
182
|
'''
|
|
157
183
|
|
|
158
|
-
|
|
159
184
|
def logPluginTrace(message: str, level: Number) -> None:
|
|
160
185
|
"""
|
|
161
186
|
If plugin trace file logging is configured, logs `message` to it.
|
|
@@ -274,6 +299,14 @@ def getModuleFilename(moduleURL: str, reload: bool, normalize: bool, base: str |
|
|
|
274
299
|
if moduleFilename:
|
|
275
300
|
# `moduleFilename` normalized to an existing script
|
|
276
301
|
return moduleFilename, None
|
|
302
|
+
if base and not _isAbsoluteModuleURL(moduleURL):
|
|
303
|
+
# Search for a matching plugin deeper in the plugin directory tree.
|
|
304
|
+
# Handles cases where a plugin exists in a nested structure, such as
|
|
305
|
+
# when a developer clones an entire repository into the plugin directory.
|
|
306
|
+
# Example: arelle/plugin/xule/plugin/xule/__init__.py
|
|
307
|
+
for path in glob("**/" + moduleURL.replace('\\', '/'), recursive=True):
|
|
308
|
+
if normalizedPath := normalizeModuleFilename(path):
|
|
309
|
+
return normalizedPath, None
|
|
277
310
|
# `moduleFilename` did not map to a local filepath or did not normalize to a script
|
|
278
311
|
# Try using `moduleURL` to search for pip-installed entry point
|
|
279
312
|
entryPointRef = EntryPointRef.get(moduleURL)
|
|
@@ -416,7 +449,7 @@ def moduleModuleInfo(
|
|
|
416
449
|
|
|
417
450
|
if moduleFilename:
|
|
418
451
|
try:
|
|
419
|
-
logPluginTrace("Scanning module for plug-in info: {}"
|
|
452
|
+
logPluginTrace(f"Scanning module for plug-in info: {moduleFilename}", logging.INFO)
|
|
420
453
|
moduleInfo = parsePluginInfo(moduleURL, moduleFilename, entryPoint)
|
|
421
454
|
if moduleInfo is None:
|
|
422
455
|
return None
|
|
@@ -426,38 +459,50 @@ def moduleModuleInfo(
|
|
|
426
459
|
del moduleInfo["importURLs"]
|
|
427
460
|
moduleImports = moduleInfo["moduleImports"]
|
|
428
461
|
del moduleInfo["moduleImports"]
|
|
429
|
-
|
|
462
|
+
moduleImportsSubtree = False
|
|
430
463
|
mergedImportURLs = []
|
|
431
464
|
|
|
432
|
-
for
|
|
433
|
-
if
|
|
465
|
+
for url in importURLs:
|
|
466
|
+
if url.startswith("module_import"):
|
|
434
467
|
for moduleImport in moduleImports:
|
|
435
468
|
mergedImportURLs.append(moduleImport + ".py")
|
|
436
|
-
if
|
|
437
|
-
|
|
438
|
-
elif
|
|
469
|
+
if url == "module_import_subtree":
|
|
470
|
+
moduleImportsSubtree = True
|
|
471
|
+
elif url == "module_subtree":
|
|
439
472
|
for _dir in os.listdir(moduleDir):
|
|
440
|
-
|
|
441
|
-
if os.path.isdir(
|
|
442
|
-
mergedImportURLs.append(
|
|
473
|
+
subtreeModule = os.path.join(moduleDir,_dir)
|
|
474
|
+
if os.path.isdir(subtreeModule) and _dir != "__pycache__":
|
|
475
|
+
mergedImportURLs.append(subtreeModule)
|
|
443
476
|
else:
|
|
444
|
-
mergedImportURLs.append(
|
|
445
|
-
if parentImportsSubtree and not
|
|
446
|
-
|
|
477
|
+
mergedImportURLs.append(url)
|
|
478
|
+
if parentImportsSubtree and not moduleImportsSubtree:
|
|
479
|
+
moduleImportsSubtree = True
|
|
447
480
|
for moduleImport in moduleImports:
|
|
448
481
|
mergedImportURLs.append(moduleImport + ".py")
|
|
449
482
|
imports = []
|
|
450
|
-
for
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
483
|
+
for url in mergedImportURLs:
|
|
484
|
+
importURL = url
|
|
485
|
+
if not _isAbsoluteModuleURL(url):
|
|
486
|
+
# Handle relative imports when plugin is loaded from external directory.
|
|
487
|
+
# When EDGAR/render imports EDGAR/validate, this works if EDGAR is in the plugin directory
|
|
488
|
+
# but fails if loaded externally (e.g., dev repo clone at /dev/path/to/EDGAR/).
|
|
489
|
+
# Solution: Find common path segments to resolve /dev/path/to/EDGAR/validate
|
|
490
|
+
# from the importing module at /dev/path/to/EDGAR/render.
|
|
491
|
+
modulePath = Path(moduleFilename)
|
|
492
|
+
importPath = Path(url)
|
|
493
|
+
if importPath.parts:
|
|
494
|
+
importFirstPart = importPath.parts[0]
|
|
495
|
+
for i, modulePathPart in enumerate(reversed(modulePath.parts)):
|
|
496
|
+
if modulePathPart != importFirstPart:
|
|
497
|
+
continue
|
|
498
|
+
# Found a potential branching point, construct and check a new path
|
|
499
|
+
candidateImportURL = str(modulePath.parents[i] / importPath)
|
|
500
|
+
if normalizeModuleFilename(candidateImportURL):
|
|
501
|
+
importURL = candidateImportURL
|
|
502
|
+
importModuleInfo = moduleModuleInfo(moduleURL=importURL, reload=reload, parentImportsSubtree=moduleImportsSubtree)
|
|
503
|
+
if importModuleInfo:
|
|
504
|
+
importModuleInfo["isImported"] = True
|
|
505
|
+
imports.append(importModuleInfo)
|
|
461
506
|
moduleInfo["imports"] = imports
|
|
462
507
|
logPluginTrace(f"Successful module plug-in info: {moduleFilename}", logging.INFO)
|
|
463
508
|
return moduleInfo
|
|
@@ -477,43 +522,30 @@ def moduleInfo(pluginInfo):
|
|
|
477
522
|
moduleInfo.getdefault('classes', []).append(name)
|
|
478
523
|
|
|
479
524
|
|
|
480
|
-
def
|
|
481
|
-
|
|
482
|
-
pluginBase: str,
|
|
483
|
-
moduleURL: str,
|
|
484
|
-
packagePrefix: str = "",
|
|
485
|
-
) -> tuple[str, str, str] | tuple[None, None, None]:
|
|
486
|
-
"""Get the name, directory and prefix of a module."""
|
|
487
|
-
moduleFilename: str
|
|
488
|
-
moduleDir: str
|
|
489
|
-
packageImportPrefix: str
|
|
525
|
+
def _isAbsoluteModuleURL(moduleURL: str) -> bool:
|
|
526
|
+
return isAbsolute(moduleURL) or isLegacyAbs(moduleURL)
|
|
490
527
|
|
|
491
|
-
moduleFilename = controller.webCache.getfilename(
|
|
492
|
-
url=moduleURL, normalize=True, base=pluginBase, allowTransformation=False
|
|
493
|
-
)
|
|
494
528
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
os.path.join(moduleFilename, "__init__.py")
|
|
505
|
-
):
|
|
506
|
-
moduleDir = os.path.dirname(moduleFilename)
|
|
507
|
-
moduleName = os.path.basename(moduleFilename)
|
|
508
|
-
packageImportPrefix = moduleName + "."
|
|
509
|
-
else:
|
|
510
|
-
moduleName = os.path.basename(moduleFilename).partition(".")[0]
|
|
511
|
-
moduleDir = os.path.dirname(moduleFilename)
|
|
512
|
-
packageImportPrefix = packagePrefix
|
|
529
|
+
def _get_name_dir_prefix(modulePath: Path, packagePrefix: str = "") -> tuple[str, str, str] | tuple[None, None, None]:
|
|
530
|
+
"""Get the name, directory and prefix of a module."""
|
|
531
|
+
moduleName = None
|
|
532
|
+
moduleDir = None
|
|
533
|
+
packageImportPrefix = None
|
|
534
|
+
initFileName = "__init__.py"
|
|
535
|
+
|
|
536
|
+
if modulePath.is_file() and modulePath.name == initFileName:
|
|
537
|
+
modulePath = modulePath.parent
|
|
513
538
|
|
|
514
|
-
|
|
539
|
+
if modulePath.is_dir() and (modulePath / initFileName).is_file():
|
|
540
|
+
moduleName = modulePath.name
|
|
541
|
+
moduleDir = str(modulePath.parent)
|
|
542
|
+
packageImportPrefix = moduleName + "."
|
|
543
|
+
elif modulePath.is_file() and modulePath.suffix == ".py":
|
|
544
|
+
moduleName = modulePath.stem
|
|
545
|
+
moduleDir = str(modulePath.parent)
|
|
546
|
+
packageImportPrefix = packagePrefix
|
|
515
547
|
|
|
516
|
-
return (
|
|
548
|
+
return (moduleName, moduleDir, packageImportPrefix)
|
|
517
549
|
|
|
518
550
|
def _get_location(moduleDir: str, moduleName: str) -> str:
|
|
519
551
|
"""Get the file name of a plugin."""
|
|
@@ -543,13 +575,9 @@ def _find_and_load_module(moduleDir: str, moduleName: str) -> ModuleType | None:
|
|
|
543
575
|
def loadModule(moduleInfo: dict[str, Any], packagePrefix: str="") -> None:
|
|
544
576
|
name = moduleInfo['name']
|
|
545
577
|
moduleURL = moduleInfo['moduleURL']
|
|
578
|
+
modulePath = Path(moduleInfo['path'])
|
|
546
579
|
|
|
547
|
-
moduleName, moduleDir, packageImportPrefix = _get_name_dir_prefix(
|
|
548
|
-
controller=_cntlr,
|
|
549
|
-
pluginBase=_pluginBase,
|
|
550
|
-
moduleURL=moduleURL,
|
|
551
|
-
packagePrefix=packagePrefix,
|
|
552
|
-
)
|
|
580
|
+
moduleName, moduleDir, packageImportPrefix = _get_name_dir_prefix(modulePath, packagePrefix)
|
|
553
581
|
|
|
554
582
|
if all(p is None for p in [moduleName, moduleDir, packageImportPrefix]):
|
|
555
583
|
_cntlr.addToLog(message=_ERROR_MESSAGE_IMPORT_TEMPLATE.format(name), level=logging.ERROR)
|
|
@@ -566,10 +594,12 @@ def loadModule(moduleInfo: dict[str, Any], packagePrefix: str="") -> None:
|
|
|
566
594
|
localeDir = os.path.dirname(module.__file__) + os.sep + pluginInfo['localeURL']
|
|
567
595
|
try:
|
|
568
596
|
_gettext = gettext.translation(pluginInfo['localeDomain'], localeDir, getLanguageCodes())
|
|
569
|
-
except
|
|
570
|
-
_gettext
|
|
597
|
+
except OSError:
|
|
598
|
+
def _gettext(x):
|
|
599
|
+
return x # no translation
|
|
571
600
|
else:
|
|
572
|
-
_gettext
|
|
601
|
+
def _gettext(x):
|
|
602
|
+
return x
|
|
573
603
|
for key, value in pluginInfo.items():
|
|
574
604
|
if key == 'name':
|
|
575
605
|
if name:
|
|
@@ -627,8 +657,7 @@ def pluginClassMethods(className: str) -> Iterator[Callable[..., Any]]:
|
|
|
627
657
|
if className in pluginInfo:
|
|
628
658
|
pluginMethodsForClass.append(pluginInfo[className])
|
|
629
659
|
pluginMethodsForClasses[className] = pluginMethodsForClass
|
|
630
|
-
|
|
631
|
-
yield method
|
|
660
|
+
yield from pluginMethodsForClass
|
|
632
661
|
|
|
633
662
|
|
|
634
663
|
def addPluginModule(name: str) -> dict[str, Any] | None:
|
arelle/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '2.37.
|
|
32
|
-
__version_tuple__ = version_tuple = (2, 37,
|
|
31
|
+
__version__ = version = '2.37.58'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 37, 58)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -58,3 +58,22 @@ PROHIBITED_HTML_TAGS = frozenset({
|
|
|
58
58
|
'select',
|
|
59
59
|
'textarea',
|
|
60
60
|
})
|
|
61
|
+
|
|
62
|
+
NUMERIC_LABEL_ROLES = frozenset({
|
|
63
|
+
'http://www.xbrl.org/2003/role/positiveLabel',
|
|
64
|
+
'http://www.xbrl.org/2003/role/positiveTerseLabel',
|
|
65
|
+
'http://www.xbrl.org/2003/role/positiveVerboseLabel',
|
|
66
|
+
'http://www.xbrl.org/2003/role/negativeLabel',
|
|
67
|
+
'http://www.xbrl.org/2003/role/negativeTerseLabel',
|
|
68
|
+
'http://www.xbrl.org/2003/role/negativeVerboseLabel',
|
|
69
|
+
'http://www.xbrl.org/2003/role/zeroLabel',
|
|
70
|
+
'http://www.xbrl.org/2003/role/zeroTerseLabel',
|
|
71
|
+
'http://www.xbrl.org/2003/role/zeroVerboseLabel',
|
|
72
|
+
'http://www.xbrl.org/2003/role/totalLabel',
|
|
73
|
+
'http://www.xbrl.org/2009/role/negatedLabel',
|
|
74
|
+
'http://www.xbrl.org/2009/role/negatedPeriodEndLabel',
|
|
75
|
+
'http://www.xbrl.org/2009/role/negatedPeriodStartLabel',
|
|
76
|
+
'http://www.xbrl.org/2009/role/negatedTotalLabel',
|
|
77
|
+
'http://www.xbrl.org/2009/role/negatedNetLabel',
|
|
78
|
+
'http://www.xbrl.org/2009/role/negatedTerseLabel',
|
|
79
|
+
})
|
|
@@ -44,6 +44,20 @@ _: TypeGetText
|
|
|
44
44
|
|
|
45
45
|
_DEBIT_QNAME_PATTERN = regex.compile('.*(Liability|Liabilities|Equity)')
|
|
46
46
|
|
|
47
|
+
STANDARD_TAXONOMY_URL_PREFIXES = frozenset((
|
|
48
|
+
'http://disclosure.edinet-fsa.go.jp/taxonomy/',
|
|
49
|
+
'https://disclosure.edinet-fsa.go.jp/taxonomy/',
|
|
50
|
+
'http://www.xbrl.org/20',
|
|
51
|
+
'https://www.xbrl.org/20',
|
|
52
|
+
'http://www.xbrl.org/lrr/',
|
|
53
|
+
'https://www.xbrl.org/lrr/',
|
|
54
|
+
'http://xbrl.org/20',
|
|
55
|
+
'https://xbrl.org/20',
|
|
56
|
+
'http://www.xbrl.org/dtr/',
|
|
57
|
+
'https://www.xbrl.org/dtr/',
|
|
58
|
+
'http://www.w3.org/1999/xlink',
|
|
59
|
+
'https://www.w3.org/1999/xlink'
|
|
60
|
+
))
|
|
47
61
|
|
|
48
62
|
@dataclass(frozen=True)
|
|
49
63
|
class UriReference:
|
|
@@ -175,6 +189,11 @@ class PluginValidationDataExtension(PluginData):
|
|
|
175
189
|
def isCorporateReport(self, modelXbrl: ModelXbrl) -> bool:
|
|
176
190
|
return self.jpcrpNamespace in modelXbrl.namespaceDocs
|
|
177
191
|
|
|
192
|
+
def isExtensionUri(self, uri: str, modelXbrl: ModelXbrl) -> bool:
|
|
193
|
+
if uri.startswith(modelXbrl.uriDir):
|
|
194
|
+
return True
|
|
195
|
+
return not any(uri.startswith(taxonomyUri) for taxonomyUri in STANDARD_TAXONOMY_URL_PREFIXES)
|
|
196
|
+
|
|
178
197
|
@lru_cache(1)
|
|
179
198
|
def isStockForm(self, modelXbrl: ModelXbrl) -> bool:
|
|
180
199
|
formTypes = self.getFormTypes(modelXbrl)
|
|
@@ -183,6 +202,18 @@ class PluginValidationDataExtension(PluginData):
|
|
|
183
202
|
for formType in formTypes
|
|
184
203
|
)
|
|
185
204
|
|
|
205
|
+
@lru_cache(1)
|
|
206
|
+
def getExtensionConcepts(self, modelXbrl: ModelXbrl) -> list[ModelConcept]:
|
|
207
|
+
"""
|
|
208
|
+
Returns a list of extension concepts in the DTS.
|
|
209
|
+
"""
|
|
210
|
+
extensionConcepts = []
|
|
211
|
+
for concepts in modelXbrl.nameConcepts.values():
|
|
212
|
+
for concept in concepts:
|
|
213
|
+
if self.isExtensionUri(concept.qname.namespaceURI, modelXbrl):
|
|
214
|
+
extensionConcepts.append(concept)
|
|
215
|
+
return extensionConcepts
|
|
216
|
+
|
|
186
217
|
def getBalanceSheets(self, modelXbrl: ModelXbrl, statement: Statement) -> list[BalanceSheet]:
|
|
187
218
|
"""
|
|
188
219
|
:return: Balance sheet data for each context/unit pairing the given statement.
|
|
@@ -27,6 +27,7 @@ from arelle.utils.Units import getDuplicateUnitGroups
|
|
|
27
27
|
from arelle.utils.validate.Decorator import validation
|
|
28
28
|
from arelle.utils.validate.Validation import Validation
|
|
29
29
|
from arelle.utils.validate.ValidationUtil import etreeIterWithDepth
|
|
30
|
+
from ..Constants import NUMERIC_LABEL_ROLES
|
|
30
31
|
from ..DisclosureSystems import (DISCLOSURE_SYSTEM_EDINET)
|
|
31
32
|
from ..PluginValidationDataExtension import PluginValidationDataExtension
|
|
32
33
|
|
|
@@ -702,6 +703,57 @@ def rule_gfm_1_3_20(
|
|
|
702
703
|
)
|
|
703
704
|
|
|
704
705
|
|
|
706
|
+
@validation(
|
|
707
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
708
|
+
disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
|
|
709
|
+
)
|
|
710
|
+
def rule_gfm_1_3_21(
|
|
711
|
+
pluginData: PluginValidationDataExtension,
|
|
712
|
+
val: ValidateXbrl,
|
|
713
|
+
*args: Any,
|
|
714
|
+
**kwargs: Any,
|
|
715
|
+
) -> Iterable[Validation]:
|
|
716
|
+
"""
|
|
717
|
+
EDINET.EC5700W: [GFM 1.3.21] Remove the tuple definition.
|
|
718
|
+
"""
|
|
719
|
+
tupleConcepts = [
|
|
720
|
+
concept for concept in pluginData.getExtensionConcepts(val.modelXbrl)
|
|
721
|
+
if concept.isTuple
|
|
722
|
+
]
|
|
723
|
+
if len(tupleConcepts) > 0:
|
|
724
|
+
yield Validation.warning(
|
|
725
|
+
codes='EDINET.EC5700W.GFM.1.3.21',
|
|
726
|
+
msg=_("Remove the tuple definition."),
|
|
727
|
+
modelObject=tupleConcepts
|
|
728
|
+
)
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
@validation(
|
|
732
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
733
|
+
disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
|
|
734
|
+
)
|
|
735
|
+
def rule_gfm_1_3_22(
|
|
736
|
+
pluginData: PluginValidationDataExtension,
|
|
737
|
+
val: ValidateXbrl,
|
|
738
|
+
*args: Any,
|
|
739
|
+
**kwargs: Any,
|
|
740
|
+
) -> Iterable[Validation]:
|
|
741
|
+
"""
|
|
742
|
+
EDINET.EC5700W: [GFM 1.3.22] Do not set the xbrldt:typedDomainRef attribute on elements defined in submitter-specific taxonomies.
|
|
743
|
+
"""
|
|
744
|
+
typedDomainConcepts = [
|
|
745
|
+
concept for concept in pluginData.getExtensionConcepts(val.modelXbrl)
|
|
746
|
+
if concept.isTypedDimension
|
|
747
|
+
]
|
|
748
|
+
|
|
749
|
+
if len(typedDomainConcepts) > 0:
|
|
750
|
+
yield Validation.warning(
|
|
751
|
+
codes='EDINET.EC5700W.GFM.1.3.22',
|
|
752
|
+
msg=_("Do not set the xbrldt:typedDomainRef attribute on elements defined in submitter-specific taxonomies."),
|
|
753
|
+
modelObject=typedDomainConcepts
|
|
754
|
+
)
|
|
755
|
+
|
|
756
|
+
|
|
705
757
|
@validation(
|
|
706
758
|
hook=ValidationHook.XBRL_FINALLY,
|
|
707
759
|
disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
|
|
@@ -886,3 +938,35 @@ def rule_gfm_1_5_8(
|
|
|
886
938
|
label=label.textValue,
|
|
887
939
|
modelObject=label
|
|
888
940
|
)
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
@validation(
|
|
944
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
945
|
+
disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
|
|
946
|
+
)
|
|
947
|
+
def rule_gfm_1_5_10(
|
|
948
|
+
pluginData: PluginValidationDataExtension,
|
|
949
|
+
val: ValidateXbrl,
|
|
950
|
+
*args: Any,
|
|
951
|
+
**kwargs: Any,
|
|
952
|
+
) -> Iterable[Validation]:
|
|
953
|
+
"""
|
|
954
|
+
EDINET.EC5700W: [GFM 1.5.10] A non-numeric concept should not have a label with a numeric role
|
|
955
|
+
"""
|
|
956
|
+
labelRelationshipSet = val.modelXbrl.relationshipSet(XbrlConst.conceptLabel)
|
|
957
|
+
if labelRelationshipSet is None:
|
|
958
|
+
return
|
|
959
|
+
for concept in val.modelXbrl.qnameConcepts.values():
|
|
960
|
+
if concept.isNumeric:
|
|
961
|
+
continue
|
|
962
|
+
labelRels = labelRelationshipSet.fromModelObject(concept)
|
|
963
|
+
for rel in labelRels:
|
|
964
|
+
label = rel.toModelObject
|
|
965
|
+
if not pluginData.isStandardTaxonomyUrl(label.modelDocument.uri, val.modelXbrl) and label.role in NUMERIC_LABEL_ROLES:
|
|
966
|
+
yield Validation.warning(
|
|
967
|
+
codes='EDINET.EC5700W.GFM.1.5.10',
|
|
968
|
+
msg=_("The non-numeric concept of '%(concept)s' has a label with a numeric role of '%(labelrole)s'"),
|
|
969
|
+
concept=concept.qname,
|
|
970
|
+
labelrole=label.role,
|
|
971
|
+
modelObject=label
|
|
972
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
arelle/Aspect.py,sha256=Pn9I91D1os1RTVj6htuxTfRzVMhmVDtrbKvV_zy9xMI,5470
|
|
2
2
|
arelle/BetaFeatures.py,sha256=T_tPac-FiozHyYLCemt0RoHJ1JahUE71L-0tHmIRKpE,858
|
|
3
|
-
arelle/Cntlr.py,sha256=
|
|
3
|
+
arelle/Cntlr.py,sha256=HQ9JfpByqRf-C-ub07ALWMWUO2LIFev8tcmqpXjHW9s,31718
|
|
4
4
|
arelle/CntlrCmdLine.py,sha256=pOztA3ExK4O-IvxELeBU0SyC4Yk6OKgbsOjpNgwmKiU,88800
|
|
5
5
|
arelle/CntlrComServer.py,sha256=h1KPf31uMbErpxTZn_iklDqUMGFgQnjZkFkFjd8gtLQ,1888
|
|
6
6
|
arelle/CntlrProfiler.py,sha256=2VQJudiUhxryVypxjODx2ccP1-n60icTiWs5lSEokhQ,972
|
|
@@ -16,12 +16,12 @@ arelle/DialogLanguage.py,sha256=HEBd21CfcJwGAGEu2gMyYHM0cXa0VVGAh-kxlZo8H9Q,7228
|
|
|
16
16
|
arelle/DialogNewFactItem.py,sha256=blcE420dyMs6GEJW-YbtPj0lwc-YTUwyyEJh_Zvq9yE,8281
|
|
17
17
|
arelle/DialogOpenArchive.py,sha256=8io1L6JhBVM8dLf23k2q7LsHCO6rpuOvknDmA3H5GSk,24004
|
|
18
18
|
arelle/DialogPackageManager.py,sha256=YyWhHNFZT-ioM5jVbTJyHoQQK6_rB83j3DzMMswQGZk,30540
|
|
19
|
-
arelle/DialogPluginManager.py,sha256=
|
|
19
|
+
arelle/DialogPluginManager.py,sha256=0Uiy2Dei_49K7jbNnEUTchqcjANPIKNYNIt29iQoV1g,33035
|
|
20
20
|
arelle/DialogRssWatch.py,sha256=mjc4pqyFDISY4tQtME0uSRQ3NlcWnNsOsMu9Zj8tTd0,13789
|
|
21
21
|
arelle/DialogURL.py,sha256=JH88OPFf588E8RW90uMaieok7A_4kOAURQ8kHWVhnao,4354
|
|
22
22
|
arelle/DialogUserPassword.py,sha256=kWPlCCihhwvsykDjanME9qBDtv6cxZlsrJyoMqiRep4,13769
|
|
23
23
|
arelle/DisclosureSystem.py,sha256=mQlz8eezPpJuG6gHBV-x4-5Hne3LVh8TQf-Qm9jiFxI,24757
|
|
24
|
-
arelle/ErrorManager.py,sha256=
|
|
24
|
+
arelle/ErrorManager.py,sha256=5BrpD9Ej8b-2JFR-GgWL32Oc2qItYnLbZApaToDKt0o,16972
|
|
25
25
|
arelle/FileSource.py,sha256=asaX2wM47T7S6kELwmXm-YjGIoV6poWz_YdYThY0lpk,47983
|
|
26
26
|
arelle/FunctionCustom.py,sha256=d1FsBG14eykvpLpgaXpN8IdxnlG54dfGcsXPYfdpA9Q,5880
|
|
27
27
|
arelle/FunctionFn.py,sha256=BcZKah1rpfquSVPwjvknM1pgFXOnK4Hr1e_ArG_mcJY,38058
|
|
@@ -53,7 +53,7 @@ arelle/ModelVersObject.py,sha256=cPD1IzhkCfuV1eMgVFWes88DH_6WkUj5kj7sgGF2M0I,260
|
|
|
53
53
|
arelle/ModelVersReport.py,sha256=bXEA9K3qkH57aABn5l-m3CTY0FAcF1yX6O4fo-URjl8,73326
|
|
54
54
|
arelle/ModelXbrl.py,sha256=oEEP-whMGZjG45BXeXabXcD_IzBp7yA-21gW6zlGe2U,61120
|
|
55
55
|
arelle/PackageManager.py,sha256=BvPExMcxh8rHMxogOag-PGbX6vXdhCiXAHcDLA6Ypsc,32592
|
|
56
|
-
arelle/PluginManager.py,sha256=
|
|
56
|
+
arelle/PluginManager.py,sha256=axNOsdpUvhths9ePeTAF3hurwrOooXA-7cGnG43z99k,42676
|
|
57
57
|
arelle/PluginUtils.py,sha256=0vFQ29wVVpU0cTY3YOBL6FhNQhhCTwShBH4qTJGLnvc,2426
|
|
58
58
|
arelle/PrototypeDtsObject.py,sha256=0lf60VcXR_isx57hBPrc7vEMkFpYkVuK4JVBSmopzkQ,7989
|
|
59
59
|
arelle/PrototypeInstanceObject.py,sha256=CXUoDllhDqpMvSQjqIYi1Ywp-J8fLhQRV9wVD2YXgVo,13204
|
|
@@ -125,7 +125,7 @@ arelle/XmlValidateConst.py,sha256=U_wN0Q-nWKwf6dKJtcu_83FXPn9c6P8JjzGA5b0w7P0,33
|
|
|
125
125
|
arelle/XmlValidateParticles.py,sha256=Mn6vhFl0ZKC_vag1mBwn1rH_x2jmlusJYqOOuxFPO2k,9231
|
|
126
126
|
arelle/XmlValidateSchema.py,sha256=6frtZOc1Yrx_5yYF6V6oHbScnglWrVbWr6xW4EHtLQI,7428
|
|
127
127
|
arelle/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
128
|
-
arelle/_version.py,sha256=
|
|
128
|
+
arelle/_version.py,sha256=DMtGvhO601kTygJwWMKYB_n05a0AM-s0DoCNqsyf8lE,708
|
|
129
129
|
arelle/typing.py,sha256=PRe-Fxwr2SBqYYUVPCJ3E7ddDX0_oOISNdT5Q97EbRM,1246
|
|
130
130
|
arelle/api/Session.py,sha256=kgSxS7VckA1sQ7xp0pJiK7IK-vRxAdAZKUo8gEx27s8,7549
|
|
131
131
|
arelle/config/creationSoftwareNames.json,sha256=5MK7XUjfDJ9OpRCCHXeOErJ1SlTBZji4WEcEOdOacx0,3128
|
|
@@ -312,14 +312,14 @@ arelle/plugin/validate/DBA/rules/tm.py,sha256=ui9oKBqlAForwkQ9kk9KBiUogTJE5pv1Rb
|
|
|
312
312
|
arelle/plugin/validate/DBA/rules/tr.py,sha256=4TootFjl0HXsKZk1XNBCyj-vnjRs4lg35hfiz_b_4wU,14684
|
|
313
313
|
arelle/plugin/validate/EBA/__init__.py,sha256=x3zXNcdSDJ3kHfL7kMs0Ve0Vs9oWbzNFVf1TK4Avmy8,45924
|
|
314
314
|
arelle/plugin/validate/EBA/config.xml,sha256=37wMVUAObK-XEqakqD8zPNog20emYt4a_yfL1AKubF8,2022
|
|
315
|
-
arelle/plugin/validate/EDINET/Constants.py,sha256=
|
|
315
|
+
arelle/plugin/validate/EDINET/Constants.py,sha256=6LVzBTt4045SxUjeQa37tlN8zYLF1QIz16khYo3eY4A,2418
|
|
316
316
|
arelle/plugin/validate/EDINET/ControllerPluginData.py,sha256=1WhiS0RdrxeXz4pGDzWATEPqCopOh2spr8Z6Qra_Psk,8420
|
|
317
317
|
arelle/plugin/validate/EDINET/CoverPageRequirements.py,sha256=ZR8pk1CQfUIi15as1zVF27W0kRlUF1M_Ygw7appDUno,4488
|
|
318
318
|
arelle/plugin/validate/EDINET/DisclosureSystems.py,sha256=3rKG42Eg-17Xx_KXU_V5yHW6I3LTwQunvf4a44C9k_4,36
|
|
319
319
|
arelle/plugin/validate/EDINET/FilingFormat.py,sha256=SFZ22zFk6RVIA9dpx3iVLlf2heKfZZqt2ZUXUje4BII,18789
|
|
320
320
|
arelle/plugin/validate/EDINET/FormType.py,sha256=jFqjJACJJ4HhkY1t6Fqei0z6rgvH3Mp-dP04KwQVv3Q,2517
|
|
321
321
|
arelle/plugin/validate/EDINET/ManifestInstance.py,sha256=o6BGlaQHSsn6D0VKH4zn59UscKnjTKlo99kSGfGdYlU,6910
|
|
322
|
-
arelle/plugin/validate/EDINET/PluginValidationDataExtension.py,sha256=
|
|
322
|
+
arelle/plugin/validate/EDINET/PluginValidationDataExtension.py,sha256=9YXy4f1EIYq4NGWaOP7dXjVStdtH4Mb4D4wACrIa2PU,22540
|
|
323
323
|
arelle/plugin/validate/EDINET/ReportFolderType.py,sha256=Q-9a-5tJfhK-cjY8WUB2AT1NI-Nn9cFtARVOIJoLRGU,2979
|
|
324
324
|
arelle/plugin/validate/EDINET/Statement.py,sha256=0Mw5IB7LMtvUZ-2xKZfxmq67xF_dCgJo3eNLweLFRHU,9350
|
|
325
325
|
arelle/plugin/validate/EDINET/UploadContents.py,sha256=o29mDoX48M3S2jQqrJO4ZaulltAPt4vD-qdsWTMCUPc,1196
|
|
@@ -332,7 +332,7 @@ arelle/plugin/validate/EDINET/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQ
|
|
|
332
332
|
arelle/plugin/validate/EDINET/rules/contexts.py,sha256=KPoyWfRaURvxoGVcWP64mTMTAKPMSmQSX06RClCLddw,7590
|
|
333
333
|
arelle/plugin/validate/EDINET/rules/edinet.py,sha256=g3IPMV5-mWbVwVmEwv5-h1LOtdfeBQ9gZI27m744FFw,12628
|
|
334
334
|
arelle/plugin/validate/EDINET/rules/frta.py,sha256=N0YglHYZuLD2IuwE26viR2ViwUYjneBuMFU9vlrS0aQ,7616
|
|
335
|
-
arelle/plugin/validate/EDINET/rules/gfm.py,sha256
|
|
335
|
+
arelle/plugin/validate/EDINET/rules/gfm.py,sha256=-NHyo6QAkKoekAc5nLSpvSwQ0lImttoSD-_y1puK-y4,36741
|
|
336
336
|
arelle/plugin/validate/EDINET/rules/manifests.py,sha256=MoT9R_a4BzuYdQVbF7RC5wz134Ve68svSdJ3NlpO_AU,4026
|
|
337
337
|
arelle/plugin/validate/EDINET/rules/upload.py,sha256=E_sEhsuUkoH648PGWwpN90uOQMjKNFaZ8priucmYMOk,47908
|
|
338
338
|
arelle/plugin/validate/ESEF/Const.py,sha256=JujF_XV-_TNsxjGbF-8SQS4OOZIcJ8zhCMnr-C1O5Ho,22660
|
|
@@ -684,9 +684,9 @@ arelle/utils/validate/ValidationUtil.py,sha256=9vmSvShn-EdQy56dfesyV8JjSRVPj7txr
|
|
|
684
684
|
arelle/utils/validate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
685
685
|
arelle/webserver/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
686
686
|
arelle/webserver/bottle.py,sha256=P-JECd9MCTNcxCnKoDUvGcoi03ezYVOgoWgv2_uH-6M,362
|
|
687
|
-
arelle_release-2.37.
|
|
688
|
-
arelle_release-2.37.
|
|
689
|
-
arelle_release-2.37.
|
|
690
|
-
arelle_release-2.37.
|
|
691
|
-
arelle_release-2.37.
|
|
692
|
-
arelle_release-2.37.
|
|
687
|
+
arelle_release-2.37.58.dist-info/licenses/LICENSE.md,sha256=Q0tn6q0VUbr-NM8916513NCIG8MNzo24Ev-sxMUBRZc,3959
|
|
688
|
+
arelle_release-2.37.58.dist-info/METADATA,sha256=R7D4feFh8MfRYsXoyMrffu1IDXMxju2PLquC1Ht1H-0,9327
|
|
689
|
+
arelle_release-2.37.58.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
690
|
+
arelle_release-2.37.58.dist-info/entry_points.txt,sha256=Uj5niwfwVsx3vaQ3fYj8hrZ1xpfCJyTUA09tYKWbzpo,111
|
|
691
|
+
arelle_release-2.37.58.dist-info/top_level.txt,sha256=fwU7SYawL4_r-sUMRg7r1nYVGjFMSDvRWx8VGAXEw7w,7
|
|
692
|
+
arelle_release-2.37.58.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|