arelle-release 2.37.39__py3-none-any.whl → 2.37.41__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/ModelInstanceObject.py +1 -1
- arelle/ValidateXbrlCalcs.py +8 -18
- arelle/_version.py +2 -2
- arelle/plugin/validate/DBA/rules/__init__.py +9 -8
- arelle/plugin/validate/DBA/rules/fr.py +3 -3
- arelle/plugin/validate/DBA/rules/tr.py +4 -2
- arelle/plugin/validate/EBA/__init__.py +7 -10
- arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +16 -0
- arelle/plugin/validate/EDINET/resources/config.xml +1 -0
- arelle/plugin/validate/EDINET/rules/edinet.py +79 -15
- arelle/plugin/validate/EDINET/rules/gfm.py +136 -0
- arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py +8 -17
- arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py +8 -17
- arelle/plugin/validate/FERC/__init__.py +6 -10
- arelle/plugin/validate/NL/PluginValidationDataExtension.py +0 -12
- arelle/plugin/validate/NL/rules/fr_nl.py +2 -4
- arelle/plugin/validate/NL/rules/nl_kvk.py +3 -3
- arelle/plugin/validate/ROS/rules/ros.py +16 -21
- arelle/utils/Contexts.py +38 -0
- arelle/utils/Equivalence.py +22 -0
- arelle/utils/Units.py +36 -0
- {arelle_release-2.37.39.dist-info → arelle_release-2.37.41.dist-info}/METADATA +1 -1
- {arelle_release-2.37.39.dist-info → arelle_release-2.37.41.dist-info}/RECORD +27 -24
- {arelle_release-2.37.39.dist-info → arelle_release-2.37.41.dist-info}/WHEEL +0 -0
- {arelle_release-2.37.39.dist-info → arelle_release-2.37.41.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.37.39.dist-info → arelle_release-2.37.41.dist-info}/licenses/LICENSE.md +0 -0
- {arelle_release-2.37.39.dist-info → arelle_release-2.37.41.dist-info}/top_level.txt +0 -0
arelle/ModelInstanceObject.py
CHANGED
|
@@ -1266,7 +1266,7 @@ class ModelContext(ModelObject):
|
|
|
1266
1266
|
|
|
1267
1267
|
def isEntityIdentifierEqualTo(self, cntx2):
|
|
1268
1268
|
"""(bool) -- True if entityIdentifier values are equal (scheme and text value)"""
|
|
1269
|
-
return self.
|
|
1269
|
+
return self.entityIdentifier == cntx2.entityIdentifier
|
|
1270
1270
|
|
|
1271
1271
|
def isEqualTo(self, cntx2, dimensionalAspectModel=None) -> bool:
|
|
1272
1272
|
if dimensionalAspectModel is None: dimensionalAspectModel = self.modelXbrl.hasXDT
|
arelle/ValidateXbrlCalcs.py
CHANGED
|
@@ -12,6 +12,8 @@ from arelle import Locale, XbrlConst, XbrlUtil
|
|
|
12
12
|
from arelle.ModelObject import ObjectPropertyViewWrapper
|
|
13
13
|
from arelle.PythonUtil import flattenSequence, strTruncate
|
|
14
14
|
from arelle.XmlValidateConst import UNVALIDATED, VALID
|
|
15
|
+
from arelle.utils.Contexts import partitionModelXbrlContexts
|
|
16
|
+
from arelle.utils.Units import partitionModelXbrlUnits
|
|
15
17
|
|
|
16
18
|
if TYPE_CHECKING:
|
|
17
19
|
from _decimal import Decimal
|
|
@@ -147,27 +149,15 @@ class ValidateXbrlCalcs:
|
|
|
147
149
|
|
|
148
150
|
# identify equal contexts
|
|
149
151
|
modelXbrl.profileActivity()
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if h in uniqueContextHashes:
|
|
154
|
-
if context.isEqualTo(uniqueContextHashes[h]):
|
|
155
|
-
self.mapContext[context] = uniqueContextHashes[h]
|
|
156
|
-
else:
|
|
157
|
-
uniqueContextHashes[h] = context
|
|
158
|
-
del uniqueContextHashes
|
|
152
|
+
for exemplar_context, *contexts in partitionModelXbrlContexts(modelXbrl).values():
|
|
153
|
+
for context in contexts:
|
|
154
|
+
self.mapContext[context] = exemplar_context
|
|
159
155
|
modelXbrl.profileActivity("... identify equal contexts", minTimeToShow=1.0)
|
|
160
156
|
|
|
161
157
|
# identify equal units
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if h in uniqueUnitHashes:
|
|
166
|
-
if unit.isEqualTo(uniqueUnitHashes[h]):
|
|
167
|
-
self.mapUnit[unit] = uniqueUnitHashes[h]
|
|
168
|
-
else:
|
|
169
|
-
uniqueUnitHashes[h] = unit
|
|
170
|
-
del uniqueUnitHashes
|
|
158
|
+
for exemplar_unit, *units in partitionModelXbrlUnits(modelXbrl).values():
|
|
159
|
+
for unit in units:
|
|
160
|
+
self.mapUnit[unit] = exemplar_unit
|
|
171
161
|
modelXbrl.profileActivity("... identify equal units", minTimeToShow=1.0)
|
|
172
162
|
|
|
173
163
|
# identify concepts participating in essence-alias relationships
|
arelle/_version.py
CHANGED
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
|
|
6
6
|
import datetime
|
|
7
7
|
import itertools
|
|
8
|
+
from collections import defaultdict
|
|
8
9
|
from collections.abc import Callable, Iterable
|
|
9
10
|
from typing import Optional, cast
|
|
10
11
|
|
|
@@ -14,6 +15,7 @@ from arelle.ModelValue import QName
|
|
|
14
15
|
from arelle.ModelXbrl import ModelXbrl
|
|
15
16
|
from arelle.typing import TypeGetText
|
|
16
17
|
from arelle.UrlUtil import scheme
|
|
18
|
+
from arelle.utils.Contexts import ContextHashKey
|
|
17
19
|
from arelle.utils.validate.Validation import Validation
|
|
18
20
|
from arelle.ValidateFilingText import parseImageDataURL
|
|
19
21
|
from arelle.ValidateXbrl import ValidateXbrl
|
|
@@ -266,19 +268,18 @@ def getFactsGroupedByContextId(modelXbrl: ModelXbrl, *conceptQns: QName) -> dict
|
|
|
266
268
|
return dict(sorted(groupedFacts.items()))
|
|
267
269
|
|
|
268
270
|
|
|
269
|
-
def groupFactsByContextHash(facts: set[ModelFact]
|
|
271
|
+
def groupFactsByContextHash(facts: set[ModelFact]) -> dict[ContextHashKey, list[ModelFact]]:
|
|
270
272
|
"""
|
|
271
|
-
Groups facts by their
|
|
272
|
-
:return: A dictionary of
|
|
273
|
+
Groups facts by their context hash key.
|
|
274
|
+
:return: A dictionary of context hash keys to list of facts.
|
|
273
275
|
"""
|
|
274
|
-
groupedFacts:
|
|
276
|
+
groupedFacts: defaultdict[ContextHashKey, list[ModelFact]] = defaultdict(list)
|
|
275
277
|
for fact in facts:
|
|
276
278
|
if fact.xValid >= VALID:
|
|
277
|
-
contextHash = fact.context
|
|
278
|
-
if contextHash not in groupedFacts:
|
|
279
|
-
groupedFacts[contextHash] = []
|
|
279
|
+
contextHash = ContextHashKey(fact.context, dimensionalAspectModel=True)
|
|
280
280
|
groupedFacts[contextHash].append(fact)
|
|
281
|
-
|
|
281
|
+
groupedFacts.default_factory = None
|
|
282
|
+
return groupedFacts
|
|
282
283
|
|
|
283
284
|
|
|
284
285
|
def lookup_namespaced_facts(modelXbrl: ModelXbrl, namespaceURI: str) -> set[ModelFact]:
|
|
@@ -602,9 +602,9 @@ def rule_fr57(
|
|
|
602
602
|
DBA.FR57.Equality(Error):
|
|
603
603
|
Assets (fsa:Assets) must equal Liabilities (fsa:LiabilitiesAndEquity)
|
|
604
604
|
"""
|
|
605
|
-
|
|
605
|
+
currentStartDateFacts = getFactsWithDimension(val, pluginData.reportingPeriodStartDateQn, pluginData.consolidatedSoloDimensionQn, [pluginData.consolidatedMemberQn, pluginData.soloMemberQn])
|
|
606
606
|
currentEndDateFacts = getFactsWithDimension(val, pluginData.reportingPeriodEndDateQn, pluginData.consolidatedSoloDimensionQn, [pluginData.consolidatedMemberQn, pluginData.soloMemberQn])
|
|
607
|
-
currentGroupedFacts = groupFactsByContextHash(
|
|
607
|
+
currentGroupedFacts = groupFactsByContextHash(currentStartDateFacts.union(currentEndDateFacts))
|
|
608
608
|
precedingEndDateFacts = getFactsWithDimension(val, pluginData.precedingReportingPeriodEndDateQn, pluginData.consolidatedSoloDimensionQn, [pluginData.consolidatedMemberQn, pluginData.soloMemberQn])
|
|
609
609
|
precedingStartDateFacts = getFactsWithDimension(val, pluginData.precedingReportingPeriodStartDateQn, pluginData.consolidatedSoloDimensionQn, [pluginData.consolidatedMemberQn, pluginData.soloMemberQn])
|
|
610
610
|
precedingGroupedFacts = groupFactsByContextHash(precedingEndDateFacts.union(precedingStartDateFacts))
|
|
@@ -635,7 +635,7 @@ def rule_fr57(
|
|
|
635
635
|
equityFacts = getFactsWithoutDimension(val, pluginData.equityQn)
|
|
636
636
|
profitLossFacts = getFactsWithoutDimension(val, pluginData.profitLossQn)
|
|
637
637
|
liabilitiesAndEquityFacts = getFactsWithoutDimension(val, pluginData.liabilitiesAndEquityQn)
|
|
638
|
-
for
|
|
638
|
+
for facts in currentGroupedFacts.values():
|
|
639
639
|
if len(facts) == 2:
|
|
640
640
|
for fact in facts:
|
|
641
641
|
if fact.qname == pluginData.reportingPeriodStartDateQn:
|
|
@@ -42,8 +42,10 @@ def rule_tr01(
|
|
|
42
42
|
gsd_facts = lookup_namespaced_facts(val.modelXbrl, NAMESPACE_GSD)
|
|
43
43
|
facts_in_error = []
|
|
44
44
|
for fact in gsd_facts:
|
|
45
|
-
if (
|
|
46
|
-
|
|
45
|
+
if not (
|
|
46
|
+
fact.context.isEntityIdentifierEqualTo(cvr_fact.context) and
|
|
47
|
+
fact.context.isPeriodEqualTo(cvr_fact.context)
|
|
48
|
+
):
|
|
47
49
|
facts_in_error.append(fact)
|
|
48
50
|
if len(facts_in_error) > 0:
|
|
49
51
|
yield Validation.error(
|
|
@@ -17,6 +17,7 @@ from arelle.ValidateUtr import ValidateUtr
|
|
|
17
17
|
from arelle.Version import authorLabel, copyrightLabel
|
|
18
18
|
from arelle.XbrlConst import qnEnumerationItemTypes
|
|
19
19
|
from arelle.ModelInstanceObject import ModelFact
|
|
20
|
+
from arelle.utils.Contexts import getDuplicateContextGroups
|
|
20
21
|
import regex as re
|
|
21
22
|
from lxml import etree
|
|
22
23
|
from collections import defaultdict
|
|
@@ -484,17 +485,13 @@ def validateFacts(val, factsToCheck):
|
|
|
484
485
|
|
|
485
486
|
del unitHashes
|
|
486
487
|
|
|
487
|
-
|
|
488
|
+
if not getattr(modelXbrl, "isStreamingMode", False):
|
|
489
|
+
for contexts in getDuplicateContextGroups(modelXbrl):
|
|
490
|
+
modelXbrl.log("WARNING" if val.isEIOPAfullVersion else "ERROR",
|
|
491
|
+
"EIOPA.S.2.7.b",
|
|
492
|
+
_("Duplicate contexts MUST NOT be reported, contexts %(cntx1)s and %(cntx2)s are equivalent.'"),
|
|
493
|
+
modelObject=contexts, cntx1=contexts[0].id, cntx2=contexts[1].id)
|
|
488
494
|
for cntx in modelXbrl.contexts.values():
|
|
489
|
-
h = cntx.contextDimAwareHash
|
|
490
|
-
if h in cntxHashes and cntx.isEqualTo(cntxHashes[h]):
|
|
491
|
-
if not getattr(modelXbrl, "isStreamingMode", False):
|
|
492
|
-
modelXbrl.log("WARNING" if val.isEIOPAfullVersion else "ERROR",
|
|
493
|
-
"EIOPA.S.2.7.b",
|
|
494
|
-
_("Duplicate contexts MUST NOT be reported, contexts %(cntx1)s and %(cntx2)s are equivalent.'"),
|
|
495
|
-
modelObject=(cntx, cntxHashes[h]), cntx1=cntx.id, cntx2=cntxHashes[h].id)
|
|
496
|
-
else:
|
|
497
|
-
cntxHashes[h] = cntx
|
|
498
495
|
for _dim in cntx.qnameDims.values():
|
|
499
496
|
_dimQn = _dim.dimensionQname
|
|
500
497
|
prefixUsed(val, _dimQn.namespaceURI, _dimQn.prefix)
|
|
@@ -10,9 +10,12 @@ from functools import lru_cache
|
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
12
|
from arelle.ModelDocument import Type as ModelDocumentType
|
|
13
|
+
from arelle.ModelInstanceObject import ModelFact
|
|
13
14
|
from arelle.ModelObject import ModelObject
|
|
15
|
+
from arelle.ModelValue import QName, qname
|
|
14
16
|
from arelle.ModelXbrl import ModelXbrl
|
|
15
17
|
from arelle.PrototypeDtsObject import LinkPrototype
|
|
18
|
+
from arelle.ValidateDuplicateFacts import getDeduplicatedFacts, DeduplicationType
|
|
16
19
|
from arelle.ValidateXbrl import ValidateXbrl
|
|
17
20
|
from arelle.typing import TypeGetText
|
|
18
21
|
from arelle.utils.PluginData import PluginData
|
|
@@ -31,8 +34,17 @@ class UploadContents:
|
|
|
31
34
|
|
|
32
35
|
@dataclass
|
|
33
36
|
class PluginValidationDataExtension(PluginData):
|
|
37
|
+
assetsIfrsQn: QName
|
|
38
|
+
liabilitiesAndEquityIfrsQn: QName
|
|
39
|
+
|
|
34
40
|
_primaryModelXbrl: ModelXbrl | None = None
|
|
35
41
|
|
|
42
|
+
def __init__(self, name: str):
|
|
43
|
+
super().__init__(name)
|
|
44
|
+
jpigpNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpigp/2024-11-01/jpigp_cor"
|
|
45
|
+
self.assetsIfrsQn = qname(jpigpNamespace, 'AssetsIFRS')
|
|
46
|
+
self.liabilitiesAndEquityIfrsQn = qname(jpigpNamespace, "LiabilitiesAndEquityIFRS")
|
|
47
|
+
|
|
36
48
|
# Identity hash for caching.
|
|
37
49
|
def __hash__(self) -> int:
|
|
38
50
|
return id(self)
|
|
@@ -63,6 +75,10 @@ class PluginValidationDataExtension(PluginData):
|
|
|
63
75
|
return False # Not a zipfile
|
|
64
76
|
return True
|
|
65
77
|
|
|
78
|
+
@lru_cache(1)
|
|
79
|
+
def getDeduplicatedFacts(self, modelXbrl: ModelXbrl) -> list[ModelFact]:
|
|
80
|
+
return getDeduplicatedFacts(modelXbrl, DeduplicationType.CONSISTENT_PAIRS)
|
|
81
|
+
|
|
66
82
|
@lru_cache(1)
|
|
67
83
|
def getFootnoteLinkElements(self, modelXbrl: ModelXbrl) -> list[ModelObject | LinkPrototype]:
|
|
68
84
|
# TODO: Consolidate with similar implementations in EDGAR and FERC
|
|
@@ -3,9 +3,11 @@ See COPYRIGHT.md for copyright information.
|
|
|
3
3
|
"""
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
from
|
|
8
|
-
from typing import Any
|
|
6
|
+
from collections import defaultdict
|
|
7
|
+
from decimal import Decimal
|
|
8
|
+
from typing import Any, Iterable, cast
|
|
9
|
+
|
|
10
|
+
import regex
|
|
9
11
|
|
|
10
12
|
from arelle import XbrlConst
|
|
11
13
|
from arelle.ValidateXbrl import ValidateXbrl
|
|
@@ -84,6 +86,13 @@ def rule_EC8033W(
|
|
|
84
86
|
and context.endDatetime is not None
|
|
85
87
|
and context.isStartEndPeriod
|
|
86
88
|
]
|
|
89
|
+
latestPriorYearContext = None
|
|
90
|
+
for priorYearContext in priorYearContexts:
|
|
91
|
+
if latestPriorYearContext is None or \
|
|
92
|
+
priorYearContext.endDatetime > latestPriorYearContext.endDatetime:
|
|
93
|
+
latestPriorYearContext = priorYearContext
|
|
94
|
+
if latestPriorYearContext is None:
|
|
95
|
+
return
|
|
87
96
|
currentYearContexts = [
|
|
88
97
|
context
|
|
89
98
|
for contextId, context in val.modelXbrl.contexts.items()
|
|
@@ -91,17 +100,72 @@ def rule_EC8033W(
|
|
|
91
100
|
and context.startDatetime is not None
|
|
92
101
|
and context.isStartEndPeriod
|
|
93
102
|
]
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
earliestCurrentYearContext = None
|
|
104
|
+
for currentYearContext in currentYearContexts:
|
|
105
|
+
if earliestCurrentYearContext is None or \
|
|
106
|
+
currentYearContext.endDatetime > earliestCurrentYearContext.startDatetime:
|
|
107
|
+
earliestCurrentYearContext = currentYearContext
|
|
108
|
+
if earliestCurrentYearContext is None:
|
|
109
|
+
return
|
|
110
|
+
if latestPriorYearContext.endDatetime > earliestCurrentYearContext.startDatetime:
|
|
111
|
+
yield Validation.warning(
|
|
112
|
+
codes='EDINET.EC8033W',
|
|
113
|
+
msg=_("The startDate element of the current year context (id=%(currentYearContextId)s) is "
|
|
114
|
+
"set to a date that is earlier than the endDate element of the prior year context "
|
|
115
|
+
"(id=%(priorYearContextId)s). Please check the corresponding context ID "
|
|
116
|
+
"%(currentYearContextId)s and %(priorYearContextId)s. Set the startDate element of "
|
|
117
|
+
"context ID %(currentYearContextId)s to a date that is later than or equal to the "
|
|
118
|
+
"endDate element of context ID %(priorYearContextId)s."),
|
|
119
|
+
currentYearContextId=earliestCurrentYearContext.id,
|
|
120
|
+
priorYearContextId=latestPriorYearContext.id,
|
|
121
|
+
modelObject=priorYearContexts + currentYearContexts,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@validation(
|
|
126
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
127
|
+
disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
|
|
128
|
+
)
|
|
129
|
+
def rule_EC8062W(
|
|
130
|
+
pluginData: PluginValidationDataExtension,
|
|
131
|
+
val: ValidateXbrl,
|
|
132
|
+
*args: Any,
|
|
133
|
+
**kwargs: Any,
|
|
134
|
+
) -> Iterable[Validation]:
|
|
135
|
+
"""
|
|
136
|
+
EDINET.EC8062W: The sum of all liabilities and equity must equal the sum of all assets.
|
|
137
|
+
"""
|
|
138
|
+
deduplicatedFacts = pluginData.getDeduplicatedFacts(val.modelXbrl)
|
|
139
|
+
contextIdPattern = regex.compile(r'^(Prior[1-9]Year|CurrentYear|Prior[1-9]Interim|Interim)(Duration|Instant)$')
|
|
140
|
+
|
|
141
|
+
factsByContextId = defaultdict(list)
|
|
142
|
+
for fact in deduplicatedFacts:
|
|
143
|
+
if fact.qname not in (pluginData.assetsIfrsQn, pluginData.liabilitiesAndEquityIfrsQn):
|
|
144
|
+
continue
|
|
145
|
+
if fact.contextID is None or not contextIdPattern.match(fact.contextID):
|
|
146
|
+
continue
|
|
147
|
+
factsByContextId[fact.contextID].append(fact)
|
|
148
|
+
|
|
149
|
+
for facts in factsByContextId.values():
|
|
150
|
+
assetSum = Decimal(0)
|
|
151
|
+
liabilitiesAndEquitySum = Decimal(0)
|
|
152
|
+
for fact in facts:
|
|
153
|
+
if isinstance(fact.xValue, float):
|
|
154
|
+
value = Decimal(fact.xValue)
|
|
155
|
+
else:
|
|
156
|
+
value = cast(Decimal, fact.xValue)
|
|
157
|
+
if fact.qname == pluginData.assetsIfrsQn:
|
|
158
|
+
assetSum += value
|
|
159
|
+
elif fact.qname == pluginData.liabilitiesAndEquityIfrsQn:
|
|
160
|
+
liabilitiesAndEquitySum += value
|
|
161
|
+
if assetSum != liabilitiesAndEquitySum:
|
|
96
162
|
yield Validation.warning(
|
|
97
|
-
codes='EDINET.
|
|
98
|
-
msg=_("The
|
|
99
|
-
"
|
|
100
|
-
"(
|
|
101
|
-
"
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
priorYearContextId=priorYearContext.id,
|
|
106
|
-
modelObject=(priorYearContext, currentYearContext),
|
|
163
|
+
codes='EDINET.EC8062W',
|
|
164
|
+
msg=_("The consolidated statement of financial position is not reconciled. "
|
|
165
|
+
"The sum of all liabilities and equity must equal the sum of all assets. "
|
|
166
|
+
"Please correct the debit (%(liabilitiesAndEquitySum)s) and credit (%(assetSum)s) "
|
|
167
|
+
"values so that they match."),
|
|
168
|
+
liabilitiesAndEquitySum=f"{liabilitiesAndEquitySum:,}",
|
|
169
|
+
assetSum=f"{assetSum:,}",
|
|
170
|
+
modelObject=facts,
|
|
107
171
|
)
|
|
@@ -3,12 +3,16 @@ See COPYRIGHT.md for copyright information.
|
|
|
3
3
|
"""
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
+
from collections import defaultdict
|
|
7
|
+
from datetime import timedelta
|
|
6
8
|
from typing import Any, cast, Iterable
|
|
7
9
|
|
|
8
10
|
import regex
|
|
9
11
|
|
|
10
12
|
from arelle import XbrlConst, XmlUtil
|
|
13
|
+
from arelle.ModelInstanceObject import ModelFact
|
|
11
14
|
from arelle.ModelObject import ModelObject
|
|
15
|
+
from arelle.ModelValue import QName
|
|
12
16
|
from arelle.PrototypeDtsObject import LocPrototype, ArcPrototype
|
|
13
17
|
from arelle.UrlUtil import isHttpUrl, splitDecodeFragment
|
|
14
18
|
from arelle.ValidateXbrl import ValidateXbrl
|
|
@@ -16,7 +20,9 @@ from arelle.ValidateXbrlCalcs import insignificantDigits
|
|
|
16
20
|
from arelle.XbrlConst import qnXbrlScenario, qnXbrldiExplicitMember, xhtmlBaseIdentifier, xmlBaseIdentifier
|
|
17
21
|
from arelle.XmlValidate import VALID
|
|
18
22
|
from arelle.typing import TypeGetText
|
|
23
|
+
from arelle.utils.Contexts import getDuplicateContextGroups
|
|
19
24
|
from arelle.utils.PluginHooks import ValidationHook
|
|
25
|
+
from arelle.utils.Units import getDuplicateUnitGroups
|
|
20
26
|
from arelle.utils.validate.Decorator import validation
|
|
21
27
|
from arelle.utils.validate.Validation import Validation
|
|
22
28
|
from arelle.utils.validate.ValidationUtil import etreeIterWithDepth
|
|
@@ -213,6 +219,136 @@ def rule_gfm_1_2_5(
|
|
|
213
219
|
)
|
|
214
220
|
|
|
215
221
|
|
|
222
|
+
@validation(
|
|
223
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
224
|
+
disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
|
|
225
|
+
)
|
|
226
|
+
def rule_gfm_1_2_7(
|
|
227
|
+
pluginData: PluginValidationDataExtension,
|
|
228
|
+
val: ValidateXbrl,
|
|
229
|
+
*args: Any,
|
|
230
|
+
**kwargs: Any,
|
|
231
|
+
) -> Iterable[Validation]:
|
|
232
|
+
"""
|
|
233
|
+
EDINET.EC5700W: [GFM 1.2.7] An instance must not contain duplicate xbrli:context elements.
|
|
234
|
+
"""
|
|
235
|
+
for contexts in getDuplicateContextGroups(val.modelXbrl):
|
|
236
|
+
yield Validation.warning(
|
|
237
|
+
codes='EDINET.EC5700W.GFM.1.2.7',
|
|
238
|
+
msg=_('Duplicate context. Remove the duplicate.'),
|
|
239
|
+
modelObject = contexts
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
@validation(
|
|
244
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
245
|
+
disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
|
|
246
|
+
)
|
|
247
|
+
def rule_gfm_1_2_8(
|
|
248
|
+
pluginData: PluginValidationDataExtension,
|
|
249
|
+
val: ValidateXbrl,
|
|
250
|
+
*args: Any,
|
|
251
|
+
**kwargs: Any,
|
|
252
|
+
) -> Iterable[Validation]:
|
|
253
|
+
"""
|
|
254
|
+
EDINET.EC5700W: [GFM 1.2.8] Every xbrli:context element must appear in at least one
|
|
255
|
+
contextRef attribute in the same instance.
|
|
256
|
+
"""
|
|
257
|
+
unused_contexts = list(set(val.modelXbrl.contexts.values()) - set(val.modelXbrl.contextsInUse))
|
|
258
|
+
unused_contexts.sort(key=lambda x: x.id)
|
|
259
|
+
for context in unused_contexts:
|
|
260
|
+
yield Validation.warning(
|
|
261
|
+
codes='EDINET.EC5700W.GFM.1.2.8',
|
|
262
|
+
msg=_('If you are not using a context, delete it if it is not needed.'),
|
|
263
|
+
modelObject = context
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@validation(
|
|
268
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
269
|
+
disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
|
|
270
|
+
)
|
|
271
|
+
def rule_gfm_1_2_9(
|
|
272
|
+
pluginData: PluginValidationDataExtension,
|
|
273
|
+
val: ValidateXbrl,
|
|
274
|
+
*args: Any,
|
|
275
|
+
**kwargs: Any,
|
|
276
|
+
) -> Iterable[Validation]:
|
|
277
|
+
"""
|
|
278
|
+
EDINET.EC5700W: [GFM 1.2.9] The same date must not appear as the content of both an xbrli:startDate and
|
|
279
|
+
an xbrli:endDate in an instance.
|
|
280
|
+
"""
|
|
281
|
+
invalidDurationContexts = []
|
|
282
|
+
for contexts in val.modelXbrl.contextsByDocument().values():
|
|
283
|
+
for context in contexts:
|
|
284
|
+
if not context.isInstantPeriod:
|
|
285
|
+
if context.endDatetime and context.startDatetime and context.startDatetime == context.endDatetime - timedelta(days=1):
|
|
286
|
+
invalidDurationContexts.append(context)
|
|
287
|
+
if len(invalidDurationContexts) > 0:
|
|
288
|
+
for context in invalidDurationContexts:
|
|
289
|
+
yield Validation.warning(
|
|
290
|
+
codes='EDINET.EC5700W.GFM.1.2.9',
|
|
291
|
+
msg=_("Set the context's startDate and endDate elements to different dates."),
|
|
292
|
+
modelObject=context
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
@validation(
|
|
297
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
298
|
+
disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
|
|
299
|
+
)
|
|
300
|
+
def rule_gfm_1_2_10(
|
|
301
|
+
pluginData: PluginValidationDataExtension,
|
|
302
|
+
val: ValidateXbrl,
|
|
303
|
+
*args: Any,
|
|
304
|
+
**kwargs: Any,
|
|
305
|
+
) -> Iterable[Validation]:
|
|
306
|
+
"""
|
|
307
|
+
EDINET.EC5700W: [GFM 1.2.10] Element xbrli:xbrl must not have duplicate child xbrli:unit elements.
|
|
308
|
+
"""
|
|
309
|
+
for duplicateUnits in getDuplicateUnitGroups(val.modelXbrl):
|
|
310
|
+
yield Validation.warning(
|
|
311
|
+
codes='EDINET.EC5700W.GFM.1.2.10',
|
|
312
|
+
msg=_('The unit element contains duplicate content. Please remove the duplicates.'),
|
|
313
|
+
modelObject = duplicateUnits
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
@validation(
|
|
318
|
+
hook=ValidationHook.XBRL_FINALLY,
|
|
319
|
+
disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
|
|
320
|
+
)
|
|
321
|
+
def rule_gfm_1_2_13(
|
|
322
|
+
pluginData: PluginValidationDataExtension,
|
|
323
|
+
val: ValidateXbrl,
|
|
324
|
+
*args: Any,
|
|
325
|
+
**kwargs: Any,
|
|
326
|
+
) -> Iterable[Validation]:
|
|
327
|
+
"""
|
|
328
|
+
EDINET.EC5700W: [GFM 1.2.13] An instance having a fact with non-nil content and the xml:lang
|
|
329
|
+
attribute of value different than the default language must also contain a fact using the same element
|
|
330
|
+
and all other attributes with an xml:lang attribute that represents the default language.
|
|
331
|
+
"""
|
|
332
|
+
defaultLang = cast(str, val.disclosureSystem.defaultXmlLang)
|
|
333
|
+
languageFacts: dict[str,dict[QName, set[ModelFact]]] = defaultdict(lambda: defaultdict(set))
|
|
334
|
+
for fact in val.modelXbrl.facts:
|
|
335
|
+
if fact.xValid >= VALID and fact.xmlLang is not None and not fact.isNil:
|
|
336
|
+
languageFacts[fact.xmlLang][fact.qname].add(fact)
|
|
337
|
+
for language, qnames in languageFacts.items():
|
|
338
|
+
if language != defaultLang:
|
|
339
|
+
for qname, facts in qnames.items():
|
|
340
|
+
matchingQnames = languageFacts[defaultLang][qname]
|
|
341
|
+
for fact in facts:
|
|
342
|
+
if not any(fact.context.isEqualTo(mq.context) for mq in matchingQnames):
|
|
343
|
+
yield Validation.warning(
|
|
344
|
+
codes='EDINET.EC5700W.GFM.1.2.13',
|
|
345
|
+
msg=_('There is an element whose xml:lang attribute is in a language other than Japanese, '
|
|
346
|
+
'but there is no element whose xml:lang attribute is in Japanese. Delete the non-Japanese element, '
|
|
347
|
+
'or set an element whose xml:lang attribute is in Japanese.'),
|
|
348
|
+
modelObject = fact
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
|
|
216
352
|
|
|
217
353
|
@validation(
|
|
218
354
|
hook=ValidationHook.XBRL_FINALLY,
|
|
@@ -24,6 +24,8 @@ from arelle.ModelRelationshipSet import ModelRelationshipSet
|
|
|
24
24
|
from arelle.ModelValue import QName, qname
|
|
25
25
|
from arelle.utils.validate.ValidationUtil import etreeIterWithDepth
|
|
26
26
|
from arelle.PythonUtil import isLegacyAbs, strTruncate
|
|
27
|
+
from arelle.utils.Contexts import partitionModelXbrlContexts
|
|
28
|
+
from arelle.utils.Units import partitionModelXbrlUnits
|
|
27
29
|
from arelle.utils.validate.DetectScriptsInXhtml import containsScriptMarkers
|
|
28
30
|
from arelle.UrlUtil import decodeBase64DataImage, isHttpUrl, scheme
|
|
29
31
|
from arelle.ValidateFilingText import parseImageDataURL
|
|
@@ -564,27 +566,17 @@ def validateXbrlFinally(val: ValidateXbrl, *args: Any, **kwargs: Any) -> None:
|
|
|
564
566
|
# identify unique contexts and units
|
|
565
567
|
mapContext = {}
|
|
566
568
|
mapUnit = {}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
if h in uniqueContextHashes:
|
|
571
|
-
if context.isEqualTo(uniqueContextHashes[h]):
|
|
572
|
-
mapContext[context] = uniqueContextHashes[h]
|
|
573
|
-
else:
|
|
574
|
-
uniqueContextHashes[h] = context
|
|
575
|
-
del uniqueContextHashes
|
|
576
|
-
uniqueUnitHashes: dict[Any, Any] = {}
|
|
569
|
+
for exemplar_context, *contexts in partitionModelXbrlContexts(modelXbrl).values():
|
|
570
|
+
for context in contexts:
|
|
571
|
+
mapContext[context] = exemplar_context
|
|
577
572
|
utrValidator = ValidateUtr(modelXbrl)
|
|
578
573
|
utrUnitIds = set(u.unitId
|
|
579
574
|
for unitItemType in utrValidator.utrItemTypeEntries.values()
|
|
580
575
|
for u in unitItemType.values())
|
|
576
|
+
for exemplar_unit, *units in partitionModelXbrlUnits(modelXbrl).values():
|
|
577
|
+
for unit in units:
|
|
578
|
+
mapUnit[unit] = exemplar_unit
|
|
581
579
|
for unit in modelXbrl.units.values():
|
|
582
|
-
h = unit.hash
|
|
583
|
-
if h in uniqueUnitHashes:
|
|
584
|
-
if unit.isEqualTo(uniqueUnitHashes[h]):
|
|
585
|
-
mapUnit[unit] = uniqueUnitHashes[h]
|
|
586
|
-
else:
|
|
587
|
-
uniqueUnitHashes[h] = unit
|
|
588
580
|
# check if any custom measure is in UTR
|
|
589
581
|
for measureTerm in unit.measures:
|
|
590
582
|
for measure in measureTerm:
|
|
@@ -594,7 +586,6 @@ def validateXbrlFinally(val: ValidateXbrl, *args: Any, **kwargs: Any) -> None:
|
|
|
594
586
|
modelXbrl.warning("ESEF.RTS.III.1.G1-7-1.customUnitInUtr",
|
|
595
587
|
_("Custom measure SHOULD NOT duplicate a UnitID of UTR: %(measure)s"),
|
|
596
588
|
modelObject=unit, measure=measure)
|
|
597
|
-
del uniqueUnitHashes
|
|
598
589
|
|
|
599
590
|
reportedMandatory: set[QName] = set()
|
|
600
591
|
precisionFacts = set()
|
|
@@ -30,6 +30,8 @@ from arelle.utils.validate.ESEFImage import ImageValidationParameters, checkSVGC
|
|
|
30
30
|
from arelle.utils.validate.ValidationUtil import etreeIterWithDepth
|
|
31
31
|
from arelle.PythonUtil import isLegacyAbs, normalizeSpace
|
|
32
32
|
from arelle.PythonUtil import strTruncate
|
|
33
|
+
from arelle.utils.Contexts import partitionModelXbrlContexts
|
|
34
|
+
from arelle.utils.Units import partitionModelXbrlUnits
|
|
33
35
|
from arelle.utils.validate.DetectScriptsInXhtml import containsScriptMarkers
|
|
34
36
|
from arelle.UrlUtil import isHttpUrl
|
|
35
37
|
from arelle.ValidateUtr import ValidateUtr
|
|
@@ -629,27 +631,17 @@ def validateXbrlFinally(val: ValidateXbrl, *args: Any, **kwargs: Any) -> None:
|
|
|
629
631
|
# identify unique contexts and units
|
|
630
632
|
mapContext = {}
|
|
631
633
|
mapUnit = {}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
if h in uniqueContextHashes:
|
|
636
|
-
if context.isEqualTo(uniqueContextHashes[h]):
|
|
637
|
-
mapContext[context] = uniqueContextHashes[h]
|
|
638
|
-
else:
|
|
639
|
-
uniqueContextHashes[h] = context
|
|
640
|
-
del uniqueContextHashes
|
|
641
|
-
uniqueUnitHashes: dict[Any, Any] = {}
|
|
634
|
+
for exemplar_context, *contexts in partitionModelXbrlContexts(modelXbrl).values():
|
|
635
|
+
for context in contexts:
|
|
636
|
+
mapContext[context] = exemplar_context
|
|
642
637
|
utrValidator = ValidateUtr(modelXbrl)
|
|
643
638
|
utrUnitIds = set(u.unitId
|
|
644
639
|
for unitItemType in utrValidator.utrItemTypeEntries.values()
|
|
645
640
|
for u in unitItemType.values())
|
|
641
|
+
for exemplar_unit, *units in partitionModelXbrlUnits(modelXbrl).values():
|
|
642
|
+
for unit in units:
|
|
643
|
+
mapUnit[unit] = exemplar_unit
|
|
646
644
|
for unit in modelXbrl.units.values():
|
|
647
|
-
h = unit.hash
|
|
648
|
-
if h in uniqueUnitHashes:
|
|
649
|
-
if unit.isEqualTo(uniqueUnitHashes[h]):
|
|
650
|
-
mapUnit[unit] = uniqueUnitHashes[h]
|
|
651
|
-
else:
|
|
652
|
-
uniqueUnitHashes[h] = unit
|
|
653
645
|
# check if any custom measure is in UTR
|
|
654
646
|
for measureTerm in unit.measures:
|
|
655
647
|
for measure in measureTerm:
|
|
@@ -659,7 +651,6 @@ def validateXbrlFinally(val: ValidateXbrl, *args: Any, **kwargs: Any) -> None:
|
|
|
659
651
|
modelXbrl.warning("ESEF.RTS.III.1.G1-7-1.customUnitInUtr",
|
|
660
652
|
_("Custom measure SHOULD NOT duplicate a UnitID of UTR: %(measure)s"),
|
|
661
653
|
modelObject=unit, measure=measure)
|
|
662
|
-
del uniqueUnitHashes
|
|
663
654
|
|
|
664
655
|
reportedMandatory: set[QName] = set()
|
|
665
656
|
precisionFacts = set()
|
|
@@ -33,6 +33,7 @@ from arelle.PrototypeDtsObject import LinkPrototype, LocPrototype, ArcPrototype
|
|
|
33
33
|
from arelle.Version import authorLabel, copyrightLabel
|
|
34
34
|
from arelle.XbrlConst import xbrli, xhtml
|
|
35
35
|
from arelle.XmlValidateConst import VALID
|
|
36
|
+
from arelle.utils.Contexts import getDuplicateContextGroups
|
|
36
37
|
|
|
37
38
|
def dislosureSystemTypes(disclosureSystem, *args, **kwargs):
|
|
38
39
|
# return ((disclosure system name, variable name), ...)
|
|
@@ -121,7 +122,6 @@ def validateXbrlFinally(val, *args, **kwargs):
|
|
|
121
122
|
|
|
122
123
|
#6.5.4 scenario
|
|
123
124
|
segContexts = set()
|
|
124
|
-
uniqueContextHashes = {}
|
|
125
125
|
contextIDs = set()
|
|
126
126
|
precisionFacts = set()
|
|
127
127
|
formType = None
|
|
@@ -133,16 +133,12 @@ def validateXbrlFinally(val, *args, **kwargs):
|
|
|
133
133
|
for c in modelXbrl.contexts.values():
|
|
134
134
|
if XmlUtil.hasChild(c, xbrli, "segment"):
|
|
135
135
|
segContexts.add(c)
|
|
136
|
-
h = c.contextDimAwareHash
|
|
137
|
-
if h in uniqueContextHashes:
|
|
138
|
-
if c.isEqualTo(uniqueContextHashes[h]):
|
|
139
|
-
modelXbrl.error("FERC.6.05.07",
|
|
140
|
-
_("The instance document contained more than one context equivalent to %(context)s (%(context2)s). "
|
|
141
|
-
"Please remove duplicate contexts from the instance."),
|
|
142
|
-
modelObject=(c, uniqueContextHashes[h]), context=c.id, context2=uniqueContextHashes[h].id)
|
|
143
|
-
else:
|
|
144
|
-
uniqueContextHashes[h] = c
|
|
145
136
|
contextIDs.add(c.id)
|
|
137
|
+
for contexts in getDuplicateContextGroups(modelXbrl):
|
|
138
|
+
modelXbrl.error("FERC.6.05.07",
|
|
139
|
+
_("The instance document contained more than one context equivalent to %(context)s (%(context2)s). "
|
|
140
|
+
"Please remove duplicate contexts from the instance."),
|
|
141
|
+
modelObject=contexts, context=contexts[0].id, context2=contexts[1].id)
|
|
146
142
|
|
|
147
143
|
if segContexts:
|
|
148
144
|
modelXbrl.error("FERC.6.05.04",
|
|
@@ -414,25 +414,13 @@ class PluginValidationDataExtension(PluginData):
|
|
|
414
414
|
calcRelSet = modelXbrl.relationshipSet(XbrlConst.summationItems)
|
|
415
415
|
dimensionalData = self.getDimensionalData(modelXbrl)
|
|
416
416
|
primaryItems = dimensionalData.primaryItems
|
|
417
|
-
domainMembers = dimensionalData.domainMembers
|
|
418
417
|
extensionData = self.getExtensionData(modelXbrl)
|
|
419
418
|
for concept in extensionData.extensionConcepts:
|
|
420
|
-
extLineItem = False
|
|
421
419
|
if concept.isPrimaryItem and \
|
|
422
420
|
not concept.isAbstract and \
|
|
423
421
|
concept in primaryItems and \
|
|
424
422
|
not widerNarrowerRelSet.contains(concept) and \
|
|
425
423
|
not calcRelSet.fromModelObject(concept):
|
|
426
|
-
extLineItem = True
|
|
427
|
-
elif concept.isAbstract and \
|
|
428
|
-
concept not in domainMembers and \
|
|
429
|
-
concept.type is not None and \
|
|
430
|
-
not concept.type.isDomainItemType and \
|
|
431
|
-
not concept.isHypercubeItem and \
|
|
432
|
-
not concept.isDimensionItem and \
|
|
433
|
-
not widerNarrowerRelSet.contains(concept):
|
|
434
|
-
extLineItem = True
|
|
435
|
-
if extLineItem:
|
|
436
424
|
if not generalSpecialRelSet.contains(concept):
|
|
437
425
|
extLineItemsNotAnchored.add(concept)
|
|
438
426
|
else:
|
|
@@ -18,6 +18,7 @@ from arelle.ModelObject import ModelObject, ModelComment
|
|
|
18
18
|
from arelle.ModelValue import QName, qname
|
|
19
19
|
from arelle.ValidateXbrl import ValidateXbrl
|
|
20
20
|
from arelle.typing import TypeGetText
|
|
21
|
+
from arelle.utils.Contexts import partitionModelXbrlContexts
|
|
21
22
|
from arelle.utils.PluginHooks import ValidationHook
|
|
22
23
|
from arelle.utils.validate.Decorator import validation
|
|
23
24
|
from arelle.utils.validate.Validation import Validation
|
|
@@ -579,10 +580,7 @@ def rule_fr_nl_3_04(
|
|
|
579
580
|
"""
|
|
580
581
|
FR-NL-3.04: An XBRL instance document MUST NOT contain duplicate 'xbrli:context' elements
|
|
581
582
|
"""
|
|
582
|
-
|
|
583
|
-
for context in val.modelXbrl.contexts.values():
|
|
584
|
-
duplicates[context.contextDimAwareHash].append(context)
|
|
585
|
-
for duplicate_contexts in duplicates.values():
|
|
583
|
+
for duplicate_contexts in partitionModelXbrlContexts(val.modelXbrl).values():
|
|
586
584
|
if len(duplicate_contexts) > 1:
|
|
587
585
|
yield Validation.error(
|
|
588
586
|
codes='NL.FR-NL-3.04',
|
|
@@ -1711,11 +1711,11 @@ def rule_nl_kvk_4_4_6_1(
|
|
|
1711
1711
|
unreportedLbLocs.add(rel.fromLocator)
|
|
1712
1712
|
if len(unreportedLbLocs) > 0:
|
|
1713
1713
|
yield Validation.warning(
|
|
1714
|
-
# Subtitle is capitalized inconsistently here because
|
|
1714
|
+
# Subtitle is capitalized inconsistently here because it matches the conformance suite. This may change in the future.
|
|
1715
1715
|
codes='NL.NL-KVK.4.4.6.1.UsableConceptsNotAppliedByTaggedFacts',
|
|
1716
1716
|
modelObject=unreportedLbLocs,
|
|
1717
|
-
msg=_('
|
|
1718
|
-
'
|
|
1717
|
+
msg=_('Concept was found but not reported on any facts. '
|
|
1718
|
+
'Remove any unused concepts or ensure concept is applied to applicable facts.'),
|
|
1719
1719
|
)
|
|
1720
1720
|
|
|
1721
1721
|
|
|
@@ -4,10 +4,11 @@ See COPYRIGHT.md for copyright information.
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
import os
|
|
7
|
-
from typing import Any
|
|
7
|
+
from typing import Any, cast
|
|
8
8
|
|
|
9
9
|
from collections import Counter
|
|
10
10
|
from collections.abc import Iterable
|
|
11
|
+
from decimal import Decimal
|
|
11
12
|
|
|
12
13
|
from arelle.typing import TypeGetText
|
|
13
14
|
from arelle.ValidateXbrl import ValidateXbrl
|
|
@@ -19,6 +20,8 @@ from arelle.ModelInstanceObject import ModelInlineFact, ModelUnit
|
|
|
19
20
|
from arelle.ModelValue import qname
|
|
20
21
|
from arelle.ModelXbrl import ModelXbrl
|
|
21
22
|
from arelle.PythonUtil import strTruncate
|
|
23
|
+
from arelle.utils.Contexts import partitionModelXbrlContexts
|
|
24
|
+
from arelle.utils.Units import partitionModelXbrlUnits
|
|
22
25
|
from arelle.utils.PluginHooks import ValidationHook
|
|
23
26
|
from arelle.utils.validate.Decorator import validation
|
|
24
27
|
from arelle.utils.validate.Validation import Validation
|
|
@@ -166,7 +169,6 @@ def rule_main(
|
|
|
166
169
|
schemeEntityIds = set()
|
|
167
170
|
mapContext = {} # identify unique contexts and units
|
|
168
171
|
mapUnit = {}
|
|
169
|
-
uniqueContextHashes: dict[str, str] = {}
|
|
170
172
|
hasCRO = False
|
|
171
173
|
unsupportedSchemeContexts = []
|
|
172
174
|
mismatchIdentifierContexts = []
|
|
@@ -179,13 +181,10 @@ def rule_main(
|
|
|
179
181
|
mismatchIdentifierContexts.append(context)
|
|
180
182
|
if scheme == "http://www.cro.ie/":
|
|
181
183
|
hasCRO = True
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
else:
|
|
187
|
-
uniqueContextHashes[h] = context
|
|
188
|
-
del uniqueContextHashes
|
|
184
|
+
for exemplar_context, *contexts in partitionModelXbrlContexts(modelXbrl).values():
|
|
185
|
+
for context in contexts:
|
|
186
|
+
mapContext[context] = exemplar_context
|
|
187
|
+
|
|
189
188
|
if len(schemeEntityIds) > 1:
|
|
190
189
|
modelXbrl.error("ROS:differentContextEntityIdentifiers",
|
|
191
190
|
_("Context entity identifier not all the same: %(schemeEntityIds)s."),
|
|
@@ -201,15 +200,9 @@ def rule_main(
|
|
|
201
200
|
modelObject=mismatchIdentifierContexts,
|
|
202
201
|
identifiers=", ".join(sorted(set(c.entityIdentifier[1] for c in mismatchIdentifierContexts))))
|
|
203
202
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if h in uniqueUnitHashes:
|
|
208
|
-
if unit.isEqualTo(uniqueUnitHashes[h]):
|
|
209
|
-
mapUnit[unit] = uniqueUnitHashes[h]
|
|
210
|
-
else:
|
|
211
|
-
uniqueUnitHashes[h] = unit
|
|
212
|
-
del uniqueUnitHashes
|
|
203
|
+
for exemplar_unit, *units in partitionModelXbrlUnits(modelXbrl).values():
|
|
204
|
+
for unit in units:
|
|
205
|
+
mapUnit[unit] = exemplar_unit
|
|
213
206
|
|
|
214
207
|
if hasCRO and "ie-common" in nsMap:
|
|
215
208
|
mandatory.add(qname("ie-common:CompaniesRegistrationOfficeNumber", nsMap)) # type-ignore[arg-type]
|
|
@@ -304,23 +297,25 @@ def rule_ros19(
|
|
|
304
297
|
"""
|
|
305
298
|
ROS: Rule 19: DPLTurnoverRevenue should be tested to be less than or equal to 10x the absolute value of Equity
|
|
306
299
|
"""
|
|
300
|
+
def convertToDecimal(value):
|
|
301
|
+
return Decimal(value) if isinstance(value, float) else cast(Decimal, value)
|
|
307
302
|
equity_facts = val.modelXbrl.factsByLocalName.get(EQUITY, set())
|
|
308
303
|
largest_equity_fact = None
|
|
309
304
|
for e_fact in equity_facts:
|
|
310
305
|
if e_fact.xValid >= VALID:
|
|
311
|
-
if largest_equity_fact is None or abs(
|
|
306
|
+
if largest_equity_fact is None or abs(convertToDecimal(e_fact.xValue)) > abs(convertToDecimal(largest_equity_fact.xValue)):
|
|
312
307
|
largest_equity_fact = e_fact
|
|
313
308
|
|
|
314
309
|
turnover_facts = val.modelXbrl.factsByLocalName.get(TURNOVER_REVENUE, set())
|
|
315
310
|
largest_turnover_fact = None
|
|
316
311
|
for t_fact in turnover_facts:
|
|
317
312
|
if t_fact.xValid >= VALID:
|
|
318
|
-
if largest_turnover_fact is None or
|
|
313
|
+
if largest_turnover_fact is None or convertToDecimal(t_fact.xValue) > convertToDecimal(largest_turnover_fact.xValue):
|
|
319
314
|
largest_turnover_fact = t_fact
|
|
320
315
|
|
|
321
316
|
if (largest_equity_fact is not None and
|
|
322
317
|
largest_turnover_fact is not None and
|
|
323
|
-
|
|
318
|
+
convertToDecimal(largest_turnover_fact.xValue)) > (10 * abs(convertToDecimal(largest_equity_fact.xValue))):
|
|
324
319
|
yield Validation.error(
|
|
325
320
|
"ROS.19",
|
|
326
321
|
_("Turnover / Revenue (DPLTurnoverRevenue) may exceed the maximum expected value. Please review the submission and, if correct, test your submission with Revenue Online's iXBRL test facility."),
|
arelle/utils/Contexts.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from arelle.utils.Equivalence import partitionIntoEquivalenceClasses
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from collections.abc import Iterable
|
|
9
|
+
from arelle.ModelXbrl import ModelXbrl
|
|
10
|
+
from arelle.ModelInstanceObject import ModelContext
|
|
11
|
+
|
|
12
|
+
class ContextHashKey:
|
|
13
|
+
__slots__ = ('context', 'dimensionalAspectModel', 'hash')
|
|
14
|
+
context: ModelContext
|
|
15
|
+
dimensionalAspectModel: bool
|
|
16
|
+
hash: int
|
|
17
|
+
|
|
18
|
+
def __init__(self, context: ModelContext, dimensionalAspectModel: bool) -> None:
|
|
19
|
+
self.context = context
|
|
20
|
+
self.dimensionalAspectModel = dimensionalAspectModel
|
|
21
|
+
self.hash = self.context.contextDimAwareHash if dimensionalAspectModel else self.context.contextNonDimAwareHash
|
|
22
|
+
|
|
23
|
+
def __eq__(self, o: Any) -> bool:
|
|
24
|
+
if isinstance(o, ContextHashKey):
|
|
25
|
+
return self.dimensionalAspectModel == o.dimensionalAspectModel and self.context.isEqualTo(o.context, self.dimensionalAspectModel)
|
|
26
|
+
return NotImplemented
|
|
27
|
+
|
|
28
|
+
def __hash__(self) -> int:
|
|
29
|
+
return self.hash
|
|
30
|
+
|
|
31
|
+
def partitionContexts(contexts: Iterable[ModelContext], dimensionalAspectModel: bool) -> dict[ContextHashKey, tuple[ModelContext, ...]]:
|
|
32
|
+
return partitionIntoEquivalenceClasses(contexts, lambda c: ContextHashKey(c, dimensionalAspectModel))
|
|
33
|
+
|
|
34
|
+
def partitionModelXbrlContexts(modelXbrl: ModelXbrl) -> dict[ContextHashKey, tuple[ModelContext, ...]]:
|
|
35
|
+
return partitionContexts(modelXbrl.contexts.values(), dimensionalAspectModel=modelXbrl.hasXDT)
|
|
36
|
+
|
|
37
|
+
def getDuplicateContextGroups(modelXbrl: ModelXbrl) -> list[tuple[ModelContext, ...]]:
|
|
38
|
+
return [partition for partition in partitionModelXbrlContexts(modelXbrl).values() if len(partition) > 1]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
from typing import (
|
|
5
|
+
TYPE_CHECKING,
|
|
6
|
+
Any,
|
|
7
|
+
Callable,
|
|
8
|
+
TypeVar,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import Iterable
|
|
13
|
+
from arelle.ModelXbrl import ModelXbrl
|
|
14
|
+
|
|
15
|
+
T = TypeVar('T')
|
|
16
|
+
K = TypeVar('K')
|
|
17
|
+
|
|
18
|
+
def partitionIntoEquivalenceClasses(items: Iterable[T], key: Callable[[T], K]) -> dict[K, tuple[T, ...]]:
|
|
19
|
+
d = defaultdict(list)
|
|
20
|
+
for item in items:
|
|
21
|
+
d[key(item)].append(item)
|
|
22
|
+
return {k: tuple(v) for k, v in d.items()}
|
arelle/utils/Units.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from arelle.utils.Equivalence import partitionIntoEquivalenceClasses
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from collections.abc import Iterable
|
|
9
|
+
from arelle.ModelXbrl import ModelXbrl
|
|
10
|
+
from arelle.ModelInstanceObject import ModelUnit
|
|
11
|
+
|
|
12
|
+
class UnitHashKey:
|
|
13
|
+
__slots__ = ('unit', 'hash')
|
|
14
|
+
unit: ModelUnit
|
|
15
|
+
hash: int
|
|
16
|
+
|
|
17
|
+
def __init__(self, unit: ModelUnit) -> None:
|
|
18
|
+
self.unit = unit
|
|
19
|
+
self.hash = self.unit.hash
|
|
20
|
+
|
|
21
|
+
def __eq__(self, o: Any) -> bool:
|
|
22
|
+
if isinstance(o, UnitHashKey):
|
|
23
|
+
return self.unit.isEqualTo(o.unit)
|
|
24
|
+
return NotImplemented
|
|
25
|
+
|
|
26
|
+
def __hash__(self) -> int:
|
|
27
|
+
return self.hash
|
|
28
|
+
|
|
29
|
+
def partitionUnits(units: Iterable[ModelUnit]) -> dict[UnitHashKey, tuple[ModelUnit, ...]]:
|
|
30
|
+
return partitionIntoEquivalenceClasses(units, UnitHashKey)
|
|
31
|
+
|
|
32
|
+
def partitionModelXbrlUnits(modelXbrl: ModelXbrl) -> dict[UnitHashKey, tuple[ModelUnit, ...]]:
|
|
33
|
+
return partitionUnits(modelXbrl.units.values())
|
|
34
|
+
|
|
35
|
+
def getDuplicateUnitGroups(modelXbrl: ModelXbrl) -> list[tuple[ModelUnit, ...]]:
|
|
36
|
+
return [partition for partition in partitionModelXbrlUnits(modelXbrl).values() if len(partition) > 1]
|
|
@@ -37,7 +37,7 @@ arelle/Locale.py,sha256=07IDxv8nIfvhyRRllFdEAKRI3yo1D2v781cTrjb_RoQ,33193
|
|
|
37
37
|
arelle/ModelDocument.py,sha256=Sq6umEdn-aNHjxIpEsXTT7A4V25nGY0JiylSnhr9zSI,130749
|
|
38
38
|
arelle/ModelDtsObject.py,sha256=nvHQs4BDmPxY6mqLiBuqIGRJXyA1EqOEGB2f3S6A6w4,88656
|
|
39
39
|
arelle/ModelFormulaObject.py,sha256=-eb0lBYciEeAvvGduIs3AHGNGrxge9_0g1cVT6UUgvc,122560
|
|
40
|
-
arelle/ModelInstanceObject.py,sha256=
|
|
40
|
+
arelle/ModelInstanceObject.py,sha256=fUiDb6aS2ls0GkrVxxkPyZqEr-RI4qsGQJjKkAK2tUk,74246
|
|
41
41
|
arelle/ModelManager.py,sha256=QUNcD2LC_YyyGFU8bFTSuzIGI1qpOK55KBlQ697Ep1I,11075
|
|
42
42
|
arelle/ModelObject.py,sha256=Rttkhv-PtfneZyDYsG5FDh98BzT97ameTmwNdqFaOv0,18657
|
|
43
43
|
arelle/ModelObjectFactory.py,sha256=XuNF4Re3p00tODCdyspfar_DNCXfARqCaLEkntgAZ0g,8750
|
|
@@ -72,7 +72,7 @@ arelle/ValidateInfoset.py,sha256=Rz_XBi5Ha43KpxXYhjLolURcWVx5qmqyjLxw48Yt9Dg,203
|
|
|
72
72
|
arelle/ValidateUtr.py,sha256=oxOPrOa1XEzBay4miXvx6eRLTnVFYUIJC9ueWUk4EkI,13633
|
|
73
73
|
arelle/ValidateVersReport.py,sha256=RMe7GlcyZV0HoVFHL0qOGrKm4et-6yPq5dmikkhnvoU,43196
|
|
74
74
|
arelle/ValidateXbrl.py,sha256=kBiY_q9QmORwC8VxGpRq9mfufknt08nEAeSgNh1ov-M,78005
|
|
75
|
-
arelle/ValidateXbrlCalcs.py,sha256=
|
|
75
|
+
arelle/ValidateXbrlCalcs.py,sha256=6OMjIef6ixJGkxH-hgIRbMRJ46e52KEo-8vDyM97krc,44028
|
|
76
76
|
arelle/ValidateXbrlDTS.py,sha256=yxvpTpImEbrQuLJ2aJf38FjA-OEznpWWdsDK0GtLXIU,104003
|
|
77
77
|
arelle/ValidateXbrlDimensions.py,sha256=Qv7_CI65SiUcpgsnEc86XuMjKz81-170wE5dmZqnvHc,38373
|
|
78
78
|
arelle/Version.py,sha256=RjbPSSiH57VzZFhhUmEmvLsL8uSb5VwEIj2zq-krhsY,934
|
|
@@ -123,7 +123,7 @@ arelle/XmlValidateConst.py,sha256=U_wN0Q-nWKwf6dKJtcu_83FXPn9c6P8JjzGA5b0w7P0,33
|
|
|
123
123
|
arelle/XmlValidateParticles.py,sha256=Mn6vhFl0ZKC_vag1mBwn1rH_x2jmlusJYqOOuxFPO2k,9231
|
|
124
124
|
arelle/XmlValidateSchema.py,sha256=6frtZOc1Yrx_5yYF6V6oHbScnglWrVbWr6xW4EHtLQI,7428
|
|
125
125
|
arelle/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
126
|
-
arelle/_version.py,sha256=
|
|
126
|
+
arelle/_version.py,sha256=U62S37dJhYrPn2KWdnBMMwXbtf-OhmJZIBOKZhfOI58,515
|
|
127
127
|
arelle/typing.py,sha256=PRe-Fxwr2SBqYYUVPCJ3E7ddDX0_oOISNdT5Q97EbRM,1246
|
|
128
128
|
arelle/api/Session.py,sha256=27HVuK3Bz1_21l4_RLn1IQg6v0MNsUEYrHajymyWwxI,7429
|
|
129
129
|
arelle/archive/CustomLogger.py,sha256=v_JXOCQLDZcfaFWzxC9FRcEf9tQi4rCI4Sx7jCuAVQI,1231
|
|
@@ -384,27 +384,27 @@ arelle/plugin/validate/DBA/PluginValidationDataExtension.py,sha256=R0lNf-3-lKHln
|
|
|
384
384
|
arelle/plugin/validate/DBA/ValidationPluginExtension.py,sha256=JozGD4LqGn8zbc_-BhZOPMJl0PSboloS6oG8UwwTz6I,48638
|
|
385
385
|
arelle/plugin/validate/DBA/__init__.py,sha256=KhmlUkqgsRtEXpu5DZBXFzv43nUTvi-0sdDNRfw5Up4,1564
|
|
386
386
|
arelle/plugin/validate/DBA/resources/config.xml,sha256=KHfo7SrjzmjHbfwIJBmESvOOjdIv4Av26BCcZxfn3Pg,875
|
|
387
|
-
arelle/plugin/validate/DBA/rules/__init__.py,sha256=
|
|
388
|
-
arelle/plugin/validate/DBA/rules/fr.py,sha256=
|
|
387
|
+
arelle/plugin/validate/DBA/rules/__init__.py,sha256=eBm6FAb_WnBBYfgLSwsO30gVjpWaHxLqRHRJAIBj7oo,10418
|
|
388
|
+
arelle/plugin/validate/DBA/rules/fr.py,sha256=IAegA_Fc-Zkjj8qlzFuo_52gNVHW-lAddBFCQw8W8P4,71318
|
|
389
389
|
arelle/plugin/validate/DBA/rules/tc.py,sha256=CXPOGHpab9Y-iV84wDXrsE-rPe_d6Uhw4HjEyTBEzq4,1572
|
|
390
390
|
arelle/plugin/validate/DBA/rules/th.py,sha256=mDrjescz6106jBGjdH6bipqx48BnxcjHSkNL1qQf0QE,6227
|
|
391
391
|
arelle/plugin/validate/DBA/rules/tm.py,sha256=ui9oKBqlAForwkQ9kk9KBiUogTJE5pv1RbIejKASprY,11797
|
|
392
|
-
arelle/plugin/validate/DBA/rules/tr.py,sha256=
|
|
393
|
-
arelle/plugin/validate/EBA/__init__.py,sha256=
|
|
392
|
+
arelle/plugin/validate/DBA/rules/tr.py,sha256=4TootFjl0HXsKZk1XNBCyj-vnjRs4lg35hfiz_b_4wU,14684
|
|
393
|
+
arelle/plugin/validate/EBA/__init__.py,sha256=x3zXNcdSDJ3kHfL7kMs0Ve0Vs9oWbzNFVf1TK4Avmy8,45924
|
|
394
394
|
arelle/plugin/validate/EBA/config.xml,sha256=37wMVUAObK-XEqakqD8zPNog20emYt4a_yfL1AKubF8,2022
|
|
395
395
|
arelle/plugin/validate/EDINET/Constants.py,sha256=QG69rWdpIrpQzZQkRcDWk2i3rlBVohr4VtSdW-IS5_w,734
|
|
396
396
|
arelle/plugin/validate/EDINET/DisclosureSystems.py,sha256=3rKG42Eg-17Xx_KXU_V5yHW6I3LTwQunvf4a44C9k_4,36
|
|
397
397
|
arelle/plugin/validate/EDINET/FormType.py,sha256=pJfKjdjqFcRLFgH6xbEixvpwatZBBHI8uI3xjjhaPI0,3175
|
|
398
398
|
arelle/plugin/validate/EDINET/Manifest.py,sha256=VWenzA1ndOp802zpTELSLREbCrzrA-nM1UCRpRf1Q3M,4849
|
|
399
|
-
arelle/plugin/validate/EDINET/PluginValidationDataExtension.py,sha256=
|
|
399
|
+
arelle/plugin/validate/EDINET/PluginValidationDataExtension.py,sha256=8w0C-H4hskBN9rho0M6wGgQfkTZMgM3aot6L0sYLVwc,7084
|
|
400
400
|
arelle/plugin/validate/EDINET/ValidationPluginExtension.py,sha256=HIGOpBOyuVs5SEh573M3IzdouRdEuNIBkdumieZi8r0,959
|
|
401
401
|
arelle/plugin/validate/EDINET/__init__.py,sha256=ew9Rc2qJe5d3XvOOFzhX6MfzxNUtxIYfxRGX-wkfR1c,3555
|
|
402
|
-
arelle/plugin/validate/EDINET/resources/config.xml,sha256=
|
|
402
|
+
arelle/plugin/validate/EDINET/resources/config.xml,sha256=7uT4GcRgk5veMLpFhPPQJxbGKiQvM52P8EMrjn0qd0g,646
|
|
403
403
|
arelle/plugin/validate/EDINET/resources/edinet-taxonomies.xml,sha256=997I3RGTLg5OY3vn5hQxVFAAxOmDSOYpuyQe6VnWSY0,16285
|
|
404
404
|
arelle/plugin/validate/EDINET/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
405
|
-
arelle/plugin/validate/EDINET/rules/edinet.py,sha256=
|
|
405
|
+
arelle/plugin/validate/EDINET/rules/edinet.py,sha256=_qrGBV667MfExFpeIygrfWbBuLFw2zrMZGNyzQNRjqA,6826
|
|
406
406
|
arelle/plugin/validate/EDINET/rules/frta.py,sha256=N0YglHYZuLD2IuwE26viR2ViwUYjneBuMFU9vlrS0aQ,7616
|
|
407
|
-
arelle/plugin/validate/EDINET/rules/gfm.py,sha256=
|
|
407
|
+
arelle/plugin/validate/EDINET/rules/gfm.py,sha256=4EKMho6eX-Ygl8yMBVabHQpbC-wxMvi067ubN9mp27U,21982
|
|
408
408
|
arelle/plugin/validate/EDINET/rules/upload.py,sha256=HZ-9Gk6WtIichTGcSsSGIrMXNgsgJYQYwfUKeLs1XWU,20369
|
|
409
409
|
arelle/plugin/validate/ESEF/Const.py,sha256=JujF_XV-_TNsxjGbF-8SQS4OOZIcJ8zhCMnr-C1O5Ho,22660
|
|
410
410
|
arelle/plugin/validate/ESEF/Dimensions.py,sha256=MOJM7vwNPEmV5cu-ZzPrhx3347ZvxgD6643OB2HRnIk,10597
|
|
@@ -412,19 +412,19 @@ arelle/plugin/validate/ESEF/Util.py,sha256=QH3btcGqBpr42M7WSKZLSdNXygZaZLfEiEjlx
|
|
|
412
412
|
arelle/plugin/validate/ESEF/__init__.py,sha256=LL7uYOcGPHgjwTlcfW2oWMqWiqrZ5yABzcKkJZFrZis,20391
|
|
413
413
|
arelle/plugin/validate/ESEF/ESEF_2021/DTS.py,sha256=6Za7BANwwc_egxLCgbgWzwUGOXZv9IF1I7JCkDNt2Tw,26277
|
|
414
414
|
arelle/plugin/validate/ESEF/ESEF_2021/Image.py,sha256=4bnhuy5viBU0viPjb4FhcRRjVVKlNdnKLFdSGg3sZvs,4871
|
|
415
|
-
arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py,sha256=
|
|
415
|
+
arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py,sha256=R3cVpiq3x0YyH5cT1L_CfAR_8onn0nHVuruFSFsszCk,63675
|
|
416
416
|
arelle/plugin/validate/ESEF/ESEF_2021/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
417
417
|
arelle/plugin/validate/ESEF/ESEF_Current/DTS.py,sha256=epp-PBh1NJzQqgxUE6C468HmoDc2w3j54rMwfiOAry4,29334
|
|
418
|
-
arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py,sha256=
|
|
418
|
+
arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py,sha256=J9hJcLlE6FA84Ppgthiu4ju0KHJ-JdmVub2qKAKm3as,74985
|
|
419
419
|
arelle/plugin/validate/ESEF/ESEF_Current/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
420
420
|
arelle/plugin/validate/ESEF/resources/authority-validations.json,sha256=bR0ZMpiQL9LqiyzrjhAGMDLEHBHimsDuDu9SQY5xofA,15503
|
|
421
421
|
arelle/plugin/validate/ESEF/resources/config.xml,sha256=t3STU_-QYM7Ay8YwZRPapnohiWVWhjfr4L2Rjx9xN9U,3902
|
|
422
|
-
arelle/plugin/validate/FERC/__init__.py,sha256=
|
|
422
|
+
arelle/plugin/validate/FERC/__init__.py,sha256=rC1OYNBWnoXowEohiR9yagHtAi_NPAlmaahRSQhSdS4,11325
|
|
423
423
|
arelle/plugin/validate/FERC/config.xml,sha256=bn9b8eCqJA1J62rYq1Nz85wJrMGAahVmmnIUQZyerjo,1919
|
|
424
424
|
arelle/plugin/validate/FERC/resources/ferc-utr.xml,sha256=OCRj9IUpdXATCBXKbB71apYx9kxcNtZW-Hq4s-avsRY,2663
|
|
425
425
|
arelle/plugin/validate/NL/DisclosureSystems.py,sha256=urRmYJ8RnGPlTgSVKW7zGN4_4CtL3OVKlcI3LwTpBz4,561
|
|
426
426
|
arelle/plugin/validate/NL/LinkbaseType.py,sha256=BwRQl4XZFFCopufC2FEMLhYENNTk2JUWVQvnIUsaqtI,3108
|
|
427
|
-
arelle/plugin/validate/NL/PluginValidationDataExtension.py,sha256=
|
|
427
|
+
arelle/plugin/validate/NL/PluginValidationDataExtension.py,sha256=4yO0UlShSFk_iWxLbCZ9SHB1wuJQMcKcDGmVkHcltIY,33672
|
|
428
428
|
arelle/plugin/validate/NL/ValidationPluginExtension.py,sha256=h6CjGJJkE8YqrzPiA8uNaCzn_P6HspH-6ja89tLCXxY,17978
|
|
429
429
|
arelle/plugin/validate/NL/__init__.py,sha256=W-SHohiAWM7Yi77gAbt-D3vvZNAB5s1j16mHCTFta6w,3158
|
|
430
430
|
arelle/plugin/validate/NL/resources/config.xml,sha256=qBE6zywFSmemBSWonuTII5iuOCUlNb1nvkpMbsZb5PM,1853
|
|
@@ -432,8 +432,8 @@ arelle/plugin/validate/NL/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
|
|
|
432
432
|
arelle/plugin/validate/NL/rules/br_kvk.py,sha256=0SwKieWzTDm3YMsXPS6zTdgbk7_Z9CzqRkRmCRz1OiQ,15789
|
|
433
433
|
arelle/plugin/validate/NL/rules/fg_nl.py,sha256=OJF2EYx4KDTdNggHiw5Trq5S5g7WGpbb7YvO6_IrrGU,10704
|
|
434
434
|
arelle/plugin/validate/NL/rules/fr_kvk.py,sha256=kYqXt45S6eM32Yg9ii7pUhOMfJaHurgYqQ73FyQALs8,8171
|
|
435
|
-
arelle/plugin/validate/NL/rules/fr_nl.py,sha256=
|
|
436
|
-
arelle/plugin/validate/NL/rules/nl_kvk.py,sha256=
|
|
435
|
+
arelle/plugin/validate/NL/rules/fr_nl.py,sha256=vwzk6_P6jhszpeboTM09uOHtm-Lijzz7Iqu7NsYKyaE,31444
|
|
436
|
+
arelle/plugin/validate/NL/rules/nl_kvk.py,sha256=KE2bOX1eQWxW1cVzMGR-HLgJ36zUq77D9DpA9-GvwNk,90165
|
|
437
437
|
arelle/plugin/validate/ROS/DisclosureSystems.py,sha256=rJ81mwQDYTi6JecFZ_zhqjjz3VNQRgjHNSh0wcQWAQE,18
|
|
438
438
|
arelle/plugin/validate/ROS/PluginValidationDataExtension.py,sha256=IV7ILhNvgKwQXqbpSA6HRNt9kEnejCyMADI3wyyIgk0,4036
|
|
439
439
|
arelle/plugin/validate/ROS/ValidationPluginExtension.py,sha256=HrLoJWHMFjou3j7ro6Ajrcab1JOgi505ZFPEM5a3QOY,776
|
|
@@ -441,7 +441,7 @@ arelle/plugin/validate/ROS/__init__.py,sha256=KuWg1MHVzA2S6eaHFptvP3Vu_5gQWf3OUY
|
|
|
441
441
|
arelle/plugin/validate/ROS/config.xml,sha256=ZCpCFgr1ZAjoUuhb1eRpDnmKrae-sXA9yl6SOWnrfm8,654
|
|
442
442
|
arelle/plugin/validate/ROS/resources/config.xml,sha256=HXWume5HlrAqOx5AtiWWqgADbRatA8YSfm_JvZGwdgQ,657
|
|
443
443
|
arelle/plugin/validate/ROS/rules/__init__.py,sha256=wW7BUAIb7sRkOxC1Amc_ZKrz03FM-Qh1TyZe6wxYaAU,1567
|
|
444
|
-
arelle/plugin/validate/ROS/rules/ros.py,sha256=
|
|
444
|
+
arelle/plugin/validate/ROS/rules/ros.py,sha256=EcPY2tQTFICNtTSR_95pdFoBRg0K7yGLlZNVYoHGpn4,19870
|
|
445
445
|
arelle/plugin/validate/UK/ValidateUK.py,sha256=0UhSwsY1lrY-EAEBJJR9QY38YXGBZ6PEgmuC5gQfBlI,57813
|
|
446
446
|
arelle/plugin/validate/UK/__init__.py,sha256=KE6s_B-EvrHDCtWQz2N_wQwyx_ZbWhYNV2GfQnluxMw,30655
|
|
447
447
|
arelle/plugin/validate/UK/config.xml,sha256=mUFhWDfBzGTn7v0ZSmf4HaweQTMJh_4ZcJmD9mzCHrA,1547
|
|
@@ -743,9 +743,12 @@ arelle/resources/libs/Tktable2.11/win-x86_64/tkTable.tcl,sha256=JrSZRngZFHtw8Svp
|
|
|
743
743
|
arelle/scripts-macOS/startWebServer.command,sha256=KXLSwAwchDZBlL-k9PYXdf39RNBtte4vV076_kIz2Ow,91
|
|
744
744
|
arelle/scripts-unix/startWebServer.sh,sha256=_0puRzaGkdMZoFn3R7hDti9a3ryN6kTZAXwLweeZU1s,42
|
|
745
745
|
arelle/scripts-windows/startWebServer.bat,sha256=qmnF1yrjNo__bi4QodONWlN0qHShVLTKptJQYyZtgcY,122
|
|
746
|
+
arelle/utils/Contexts.py,sha256=j9uSBAXGkunlJGC9SscCbb1cj3oU_J3b_yjdhj2B4a4,1714
|
|
746
747
|
arelle/utils/EntryPointDetection.py,sha256=4RzercL0xE4PJrwoeUYq3S-E7PMSD-IspyS9bwK2RYM,4722
|
|
748
|
+
arelle/utils/Equivalence.py,sha256=Ac6sENvh-WHJlBJneV_-6n_MF2C1filHETkUEiucLJg,525
|
|
747
749
|
arelle/utils/PluginData.py,sha256=GUnuZaApm1J4Xm9ZA1U2M1aask-AaNGviLtc0fgXbFg,265
|
|
748
750
|
arelle/utils/PluginHooks.py,sha256=CeVxti23VjERQl4xWFucDVTW63TCG2PUdnxpjd3x_Ms,31170
|
|
751
|
+
arelle/utils/Units.py,sha256=c9bwnu9Xnm00gC9Q6qQ1ogsEeTEXGRH7rahlEbrEWnQ,1201
|
|
749
752
|
arelle/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
750
753
|
arelle/utils/validate/Decorator.py,sha256=8LGmA171HZgKrALtsMKyHqMNM-XCdwJOv6KpZz4pC2c,3161
|
|
751
754
|
arelle/utils/validate/DetectScriptsInXhtml.py,sha256=RFBh_Z24OjR69s71qQzSzbxdU-WCTWuvYlONN-BgpZ0,2098
|
|
@@ -756,9 +759,9 @@ arelle/utils/validate/ValidationUtil.py,sha256=9vmSvShn-EdQy56dfesyV8JjSRVPj7txr
|
|
|
756
759
|
arelle/utils/validate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
757
760
|
arelle/webserver/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
758
761
|
arelle/webserver/bottle.py,sha256=P-JECd9MCTNcxCnKoDUvGcoi03ezYVOgoWgv2_uH-6M,362
|
|
759
|
-
arelle_release-2.37.
|
|
760
|
-
arelle_release-2.37.
|
|
761
|
-
arelle_release-2.37.
|
|
762
|
-
arelle_release-2.37.
|
|
763
|
-
arelle_release-2.37.
|
|
764
|
-
arelle_release-2.37.
|
|
762
|
+
arelle_release-2.37.41.dist-info/licenses/LICENSE.md,sha256=Q0tn6q0VUbr-NM8916513NCIG8MNzo24Ev-sxMUBRZc,3959
|
|
763
|
+
arelle_release-2.37.41.dist-info/METADATA,sha256=35ud-2G1jCFZ1rgVkMj7AQIZ8CcLkQ5z4mNH49402-E,9137
|
|
764
|
+
arelle_release-2.37.41.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
765
|
+
arelle_release-2.37.41.dist-info/entry_points.txt,sha256=Uj5niwfwVsx3vaQ3fYj8hrZ1xpfCJyTUA09tYKWbzpo,111
|
|
766
|
+
arelle_release-2.37.41.dist-info/top_level.txt,sha256=fwU7SYawL4_r-sUMRg7r1nYVGjFMSDvRWx8VGAXEw7w,7
|
|
767
|
+
arelle_release-2.37.41.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|