arelle-release 2.37.71__py3-none-any.whl → 2.38.0__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.
- arelle/BetaFeatures.py +0 -21
- arelle/Cntlr.py +7 -1
- arelle/CntlrCmdLine.py +95 -19
- arelle/CntlrWinMain.py +4 -1
- arelle/DialogFind.py +1 -1
- arelle/ModelDtsObject.py +2 -0
- arelle/ModelObject.py +16 -18
- arelle/ModelObjectFactory.py +17 -15
- arelle/ModelXbrl.py +7 -1
- arelle/PluginManager.py +1 -5
- arelle/RuntimeOptions.py +1 -0
- arelle/UrlUtil.py +11 -0
- arelle/Validate.py +3 -3
- arelle/ValidateXbrl.py +2 -1
- arelle/ValidateXbrlCalcs.py +210 -186
- arelle/WebCache.py +2 -8
- arelle/XbrlConst.py +2 -0
- arelle/XmlUtil.py +16 -21
- arelle/XmlValidate.py +4 -6
- arelle/_version.py +2 -2
- arelle/config/rosettaEntitlements.plist +8 -0
- arelle/conformance/CSVTestcaseLoader.py +1 -1
- arelle/formula/XPathContext.py +3 -3
- arelle/logging/formatters/LogFormatter.py +3 -1
- arelle/packages/report/ReportPackage.py +9 -1
- arelle/plugin/inlineXbrlDocumentSet.py +1 -3
- arelle/plugin/validate/DBA/DisclosureSystems.py +19 -1
- arelle/plugin/validate/DBA/resources/config.xml +5 -0
- arelle/plugin/validate/DBA/rules/fr.py +19 -2
- arelle/plugin/validate/DBA/rules/tc.py +2 -0
- arelle/plugin/validate/DBA/rules/th.py +6 -0
- arelle/plugin/validate/DBA/rules/tm.py +18 -5
- arelle/plugin/validate/DBA/rules/tr.py +11 -5
- arelle/plugin/validate/EDINET/ControllerPluginData.py +2 -1
- arelle/plugin/validate/EDINET/NamespaceConfig.py +50 -0
- arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +33 -78
- arelle/plugin/validate/EDINET/TableOfContentsBuilder.py +153 -51
- arelle/plugin/validate/EDINET/rules/contexts.py +1 -1
- arelle/plugin/validate/EDINET/rules/edinet.py +163 -20
- arelle/plugin/validate/EDINET/rules/gfm.py +88 -1
- arelle/plugin/validate/EDINET/rules/upload.py +1 -1
- arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py +3 -3
- arelle/plugin/validate/ESEF/ESEF_Current/DTS.py +42 -14
- arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py +14 -3
- arelle/plugin/validate/ESEF/__init__.py +10 -5
- arelle/plugin/validate/ESEF/resources/authority-validations.json +10 -5
- arelle/plugin/validate/NL/DisclosureSystems.py +22 -0
- arelle/plugin/validate/NL/PluginValidationDataExtension.py +20 -0
- arelle/plugin/validate/NL/ValidationPluginExtension.py +48 -3
- arelle/plugin/validate/NL/resources/config.xml +18 -0
- arelle/plugin/validate/NL/rules/br_kvk.py +9 -54
- arelle/plugin/validate/NL/rules/fg_nl.py +7 -38
- arelle/plugin/validate/NL/rules/fr_kvk.py +7 -42
- arelle/plugin/validate/NL/rules/fr_nl.py +25 -140
- arelle/plugin/validate/NL/rules/nl_kvk.py +125 -12
- arelle/plugin/validate/ROS/rules/ros.py +3 -1
- arelle/plugin/validate/UK/__init__.py +70 -14
- arelle/utils/EntryPointDetection.py +17 -11
- arelle/utils/validate/ESEFImage.py +3 -3
- arelle/utils/validate/Validation.py +9 -0
- arelle/utils/validate/ValidationPlugin.py +14 -12
- {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/METADATA +10 -5
- {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/RECORD +67 -69
- {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/licenses/LICENSE.md +0 -3
- arelle/model/CommentBase.py +0 -9
- arelle/model/ElementBase.py +0 -11
- arelle/model/PIBase.py +0 -10
- arelle/model/__init__.py +0 -15
- {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/WHEEL +0 -0
- {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.37.71.dist-info → arelle_release-2.38.0.dist-info}/top_level.txt +0 -0
arelle/ValidateXbrlCalcs.py
CHANGED
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
from collections import defaultdict, OrderedDict
|
|
6
6
|
from math import (log10, isnan, isinf, fabs, floor, pow)
|
|
7
7
|
import decimal
|
|
8
|
-
from typing import TYPE_CHECKING
|
|
8
|
+
from typing import TYPE_CHECKING, Iterable
|
|
9
9
|
from regex import compile as re_compile
|
|
10
10
|
import hashlib
|
|
11
11
|
from arelle import Locale, XbrlConst, XbrlUtil
|
|
@@ -14,6 +14,7 @@ from arelle.PythonUtil import flattenSequence, strTruncate
|
|
|
14
14
|
from arelle.XmlValidateConst import UNVALIDATED, VALID
|
|
15
15
|
from arelle.utils.Contexts import partitionModelXbrlContexts
|
|
16
16
|
from arelle.utils.Units import partitionModelXbrlUnits
|
|
17
|
+
from arelle.utils.validate.Validation import Validation
|
|
17
18
|
|
|
18
19
|
if TYPE_CHECKING:
|
|
19
20
|
from _decimal import Decimal
|
|
@@ -92,8 +93,8 @@ EMPTY_SET = set()
|
|
|
92
93
|
def rangeToStr(a, b, inclA, inclB) -> str:
|
|
93
94
|
return {True:"[", False: "("}[inclA] + f"{a}, {b}" + {True:"]", False: ")"}[inclB]
|
|
94
95
|
|
|
95
|
-
def validate(modelXbrl, validateCalcs) ->
|
|
96
|
-
ValidateXbrlCalcs(modelXbrl, validateCalcs).validate()
|
|
96
|
+
def validate(modelXbrl, validateCalcs) -> Iterable[Validation]:
|
|
97
|
+
yield from ValidateXbrlCalcs(modelXbrl, validateCalcs).validate()
|
|
97
98
|
|
|
98
99
|
class ValidateXbrlCalcs:
|
|
99
100
|
def __init__(self, modelXbrl, validateCalcs):
|
|
@@ -120,7 +121,7 @@ class ValidateXbrlCalcs:
|
|
|
120
121
|
self.requiresElementFacts = defaultdict(list)
|
|
121
122
|
self.conceptsInRequiresElement = set()
|
|
122
123
|
|
|
123
|
-
def validate(self):
|
|
124
|
+
def validate(self) -> Iterable[Validation]:
|
|
124
125
|
# note that calc linkbase checks need to be performed even if no facts in instance (e.g., to detect duplicate relationships)
|
|
125
126
|
modelXbrl = self.modelXbrl
|
|
126
127
|
xbrl21 = self.xbrl21
|
|
@@ -142,10 +143,16 @@ class ValidateXbrlCalcs:
|
|
|
142
143
|
oimErrs.add(e)
|
|
143
144
|
if any(e == "xbrlxe:unsupportedTuple" for e in oimErrs):
|
|
144
145
|
# ignore this error and change to warning
|
|
145
|
-
|
|
146
|
+
yield Validation.warning(
|
|
147
|
+
"calc11e:tuplesInReportWarning",
|
|
148
|
+
_("Validating of calculations ignores tuples."),
|
|
149
|
+
)
|
|
146
150
|
if any(e in oimXbrlxeBlockingErrorCodes for e in oimErrs if e != "xbrlxe:unsupportedTuple"):
|
|
147
|
-
|
|
148
|
-
|
|
151
|
+
yield Validation.warning(
|
|
152
|
+
"calc11e:oimIncompatibleReportWarning",
|
|
153
|
+
_("Validating of calculations is skipped due to OIM errors."),
|
|
154
|
+
)
|
|
155
|
+
return
|
|
149
156
|
|
|
150
157
|
# identify equal contexts
|
|
151
158
|
modelXbrl.profileActivity()
|
|
@@ -165,14 +172,19 @@ class ValidateXbrlCalcs:
|
|
|
165
172
|
if xbrl21:
|
|
166
173
|
for baseSetKey in modelXbrl.baseSets.keys():
|
|
167
174
|
arcrole, ELR, linkqname, arcqname = baseSetKey
|
|
168
|
-
if
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
if (
|
|
176
|
+
not ELR or
|
|
177
|
+
not linkqname or
|
|
178
|
+
not arcqname or
|
|
179
|
+
arcrole not in (XbrlConst.essenceAlias, XbrlConst.requiresElement)
|
|
180
|
+
):
|
|
181
|
+
continue
|
|
182
|
+
conceptsSet = {XbrlConst.essenceAlias:self.conceptsInEssencesAlias,
|
|
183
|
+
XbrlConst.requiresElement:self.conceptsInRequiresElement}[arcrole]
|
|
184
|
+
for modelRel in modelXbrl.relationshipSet(arcrole,ELR,linkqname,arcqname).modelRelationships:
|
|
185
|
+
for concept in (modelRel.fromModelObject, modelRel.toModelObject):
|
|
186
|
+
if concept is not None and concept.qname is not None:
|
|
187
|
+
conceptsSet.add(concept)
|
|
176
188
|
modelXbrl.profileActivity("... identify requires-element and esseance-aliased concepts", minTimeToShow=1.0)
|
|
177
189
|
|
|
178
190
|
self.bindFacts(modelXbrl.facts,[modelXbrl.modelDocument.xmlRootElement])
|
|
@@ -188,168 +200,180 @@ class ValidateXbrlCalcs:
|
|
|
188
200
|
# identify calcluation & essence-alias base sets (by key)
|
|
189
201
|
for baseSetKey in modelXbrl.baseSets.keys():
|
|
190
202
|
arcrole, ELR, linkqname, arcqname = baseSetKey
|
|
191
|
-
if
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
203
|
+
if (
|
|
204
|
+
not ELR or
|
|
205
|
+
not linkqname or
|
|
206
|
+
not arcqname or
|
|
207
|
+
arcrole not in allArcroles
|
|
208
|
+
):
|
|
209
|
+
continue
|
|
210
|
+
relsSet = modelXbrl.relationshipSet(arcrole,ELR,linkqname,arcqname)
|
|
211
|
+
sumConceptItemRels.clear()
|
|
212
|
+
if arcrole in summationArcroles:
|
|
213
|
+
fromRelationships = relsSet.fromModelObjects()
|
|
214
|
+
for sumConcept, modelRels in fromRelationships.items():
|
|
215
|
+
sumBindingKeys = self.sumConceptBindKeys[sumConcept]
|
|
216
|
+
dupBindingKeys = set()
|
|
217
|
+
boundSumKeys = set()
|
|
218
|
+
# determine boundSums
|
|
219
|
+
for modelRel in modelRels:
|
|
220
|
+
itemConcept = modelRel.toModelObject
|
|
221
|
+
if itemConcept is not None and itemConcept.qname is not None:
|
|
222
|
+
itemBindingKeys = self.itemConceptBindKeys[itemConcept]
|
|
223
|
+
boundSumKeys |= sumBindingKeys & itemBindingKeys
|
|
224
|
+
if calc11:
|
|
225
|
+
siRels = sumConceptItemRels[sumConcept]
|
|
226
|
+
if itemConcept in siRels:
|
|
227
|
+
yield Validation.error('calc11e:duplicateCalculationRelationships',
|
|
228
|
+
_("Duplicate summation-item relationships from total concept %(sumConcept)s to contributing concept %(itemConcept)s in link role %(linkrole)s"),
|
|
229
|
+
modelObject=(siRels[itemConcept], modelRel), linkrole=modelRel.linkrole,
|
|
230
|
+
sumConcept=sumConcept.qname, itemConcept=itemConcept.qname)
|
|
231
|
+
siRels[itemConcept] = modelRel
|
|
232
|
+
if not sumConcept.isDecimal or not itemConcept.isDecimal:
|
|
233
|
+
yield Validation.error('calc11e:nonDecimalItemNode',
|
|
234
|
+
_("The source and target of a Calculations v1.1 relationship MUST both be decimal concepts: %(sumConcept)s, %(itemConcept)s, link role %(linkrole)s"),
|
|
235
|
+
modelObject=(sumConcept, itemConcept, modelRel), linkrole=modelRel.linkrole,
|
|
236
|
+
sumConcept=sumConcept.qname, itemConcept=itemConcept.qname)
|
|
237
|
+
|
|
238
|
+
# add up rounded items
|
|
239
|
+
boundSums = defaultdict(decimal.Decimal) # sum of facts meeting factKey
|
|
240
|
+
boundIntervals = {} # interval sum of facts meeting factKey
|
|
241
|
+
blockedIntervals = set() # bind Keys for summations which have an inconsistency
|
|
242
|
+
boundSummationItems = defaultdict(list) # corresponding fact refs for messages
|
|
243
|
+
boundIntervalItems = defaultdict(list) # corresponding fact refs for messages
|
|
244
|
+
for modelRel in modelRels:
|
|
245
|
+
w = modelRel.weightDecimal
|
|
246
|
+
itemConcept = modelRel.toModelObject
|
|
247
|
+
if itemConcept is None:
|
|
248
|
+
continue
|
|
249
|
+
for itemBindKey in boundSumKeys:
|
|
250
|
+
ancestor, contextHash, unit = itemBindKey
|
|
251
|
+
factKey = (itemConcept, ancestor, contextHash, unit)
|
|
252
|
+
_itemFacts = self.itemFacts.get(factKey,())
|
|
253
|
+
if xbrl21:
|
|
254
|
+
for fact in _itemFacts:
|
|
255
|
+
if not fact.isNil:
|
|
256
|
+
if fact in self.duplicatedFacts:
|
|
257
|
+
dupBindingKeys.add(itemBindKey)
|
|
258
|
+
elif fact not in self.consistentDupFacts:
|
|
259
|
+
roundedValue = roundFact(fact, self.inferDecimals)
|
|
260
|
+
boundSums[itemBindKey] += roundedValue * w
|
|
261
|
+
boundSummationItems[itemBindKey].append(wrappedFactWithWeight(fact,w,roundedValue))
|
|
262
|
+
if calc11 and _itemFacts:
|
|
263
|
+
validation, (y1, y2, iY1, iY2) = self.consistentFactValueInterval(_itemFacts, calc11t)
|
|
264
|
+
if validation is not None:
|
|
265
|
+
yield validation
|
|
266
|
+
if y1 is INCONSISTENT:
|
|
267
|
+
blockedIntervals.add(itemBindKey)
|
|
268
|
+
elif y1 is not NIL_FACT_SET:
|
|
269
|
+
x1, x2, iX1, iX2 = boundIntervals.get(itemBindKey, ZERO_RANGE)
|
|
270
|
+
y1 *= w
|
|
271
|
+
y2 *= w
|
|
272
|
+
if y2 < y1:
|
|
273
|
+
y1, y2 = y2, y1
|
|
274
|
+
boundIntervals[itemBindKey] = (x1 + y1, x2 + y2, iX1 and iY1, iX2 and iY2)
|
|
275
|
+
boundIntervalItems[itemBindKey].extend(_itemFacts)
|
|
276
|
+
for sumBindKey in boundSumKeys:
|
|
277
|
+
ancestor, contextHash, unit = sumBindKey
|
|
278
|
+
factKey = (sumConcept, ancestor, contextHash, unit)
|
|
279
|
+
if factKey not in self.sumFacts:
|
|
280
|
+
continue
|
|
281
|
+
sumFacts = self.sumFacts[factKey]
|
|
282
|
+
if xbrl21:
|
|
283
|
+
for fact in sumFacts:
|
|
284
|
+
if fact.isNil:
|
|
285
|
+
continue
|
|
286
|
+
if fact in self.duplicatedFacts:
|
|
287
|
+
dupBindingKeys.add(sumBindKey)
|
|
288
|
+
elif (sumBindKey in boundSums and sumBindKey not in dupBindingKeys
|
|
289
|
+
and fact not in self.consistentDupFacts
|
|
290
|
+
and not (len(sumFacts) > 1 and not self.deDuplicate)): # don't bind if sum duplicated without dedup option
|
|
291
|
+
roundedSum = roundFact(fact, self.inferDecimals)
|
|
292
|
+
roundedItemsSum = roundFact(fact, self.inferDecimals, vDecimal=boundSums[sumBindKey])
|
|
293
|
+
if roundedItemsSum != roundFact(fact, self.inferDecimals):
|
|
294
|
+
d = inferredDecimals(fact)
|
|
295
|
+
if isnan(d) or isinf(d): d = 4
|
|
296
|
+
_boundSummationItems = boundSummationItems[sumBindKey]
|
|
297
|
+
unreportedContribingItemQnames = [] # list the missing/unreported contributors in relationship order
|
|
298
|
+
for modelRel in modelRels:
|
|
299
|
+
itemConcept = modelRel.toModelObject
|
|
300
|
+
if (itemConcept is not None and
|
|
301
|
+
(itemConcept, ancestor, contextHash, unit) not in self.itemFacts):
|
|
302
|
+
unreportedContribingItemQnames.append(str(itemConcept.qname))
|
|
303
|
+
yield Validation.inconsistency("xbrl.5.2.5.2:calcInconsistency",
|
|
304
|
+
_("Calculation inconsistent from %(concept)s in link role %(linkrole)s reported sum %(reportedSum)s computed sum %(computedSum)s context %(contextID)s unit %(unitID)s unreportedContributingItems %(unreportedContributors)s"),
|
|
305
|
+
modelObject=wrappedSummationAndItems(fact, roundedSum, _boundSummationItems),
|
|
306
|
+
concept=sumConcept.qname, linkrole=ELR,
|
|
307
|
+
linkroleDefinition=modelXbrl.roleTypeDefinition(ELR),
|
|
308
|
+
reportedSum=Locale.format_decimal(modelXbrl.locale, roundedSum, 1, max(d,0)),
|
|
309
|
+
computedSum=Locale.format_decimal(modelXbrl.locale, roundedItemsSum, 1, max(d,0)),
|
|
310
|
+
contextID=fact.context.id, unitID=fact.unit.id if fact.unit is not None else "(none)",
|
|
311
|
+
unreportedContributors=", ".join(unreportedContribingItemQnames) or "none")
|
|
312
|
+
del unreportedContribingItemQnames[:]
|
|
313
|
+
if calc11:
|
|
314
|
+
validation, (s1, s2, incls1, incls2) = self.consistentFactValueInterval(sumFacts, calc11t)
|
|
315
|
+
if validation is not None:
|
|
316
|
+
yield validation
|
|
317
|
+
if s1 is not INCONSISTENT and s1 is not NIL_FACT_SET and sumBindKey not in blockedIntervals and sumBindKey in boundIntervals:
|
|
318
|
+
x1, x2, inclx1, inclx2 = boundIntervals[sumBindKey]
|
|
319
|
+
a = max(s1, x1)
|
|
320
|
+
b = min(s2, x2)
|
|
321
|
+
inclA = incls1 | inclx1
|
|
322
|
+
inclB = incls2 | inclx2
|
|
323
|
+
if (a == b and not (inclA and inclB)) or (a > b):
|
|
324
|
+
yield Validation.inconsistency("calc11e:inconsistentCalculationUsing" + self.calc11suffix,
|
|
325
|
+
_("Calculation inconsistent from %(concept)s in link role %(linkrole)s reported sum %(reportedSum)s computed sum %(computedSum)s context %(contextID)s unit %(unitID)s"),
|
|
326
|
+
modelObject=sumFacts + boundIntervalItems[sumBindKey],
|
|
327
|
+
concept=sumConcept.qname, linkrole=ELR,
|
|
328
|
+
linkroleDefinition=modelXbrl.roleTypeDefinition(ELR),
|
|
329
|
+
reportedSum=rangeToStr(s1,s2,incls1,incls2),
|
|
330
|
+
computedSum=rangeToStr(x1,x2,inclx1,inclx2),
|
|
331
|
+
contextID=sumFacts[0].context.id, unitID=sumFacts[0].unit.id if sumFacts[0].unit is not None else "(none)")
|
|
332
|
+
boundSummationItems.clear() # dereference facts in list
|
|
333
|
+
boundIntervalItems.clear()
|
|
334
|
+
elif arcrole == XbrlConst.essenceAlias:
|
|
335
|
+
for modelRel in relsSet.modelRelationships:
|
|
336
|
+
essenceConcept = modelRel.fromModelObject
|
|
337
|
+
aliasConcept = modelRel.toModelObject
|
|
338
|
+
essenceBindingKeys = self.esAlConceptBindKeys[essenceConcept]
|
|
339
|
+
aliasBindingKeys = self.esAlConceptBindKeys[aliasConcept]
|
|
340
|
+
for esAlBindKey in essenceBindingKeys & aliasBindingKeys:
|
|
341
|
+
ancestor, contextHash = esAlBindKey
|
|
342
|
+
essenceFactsKey = (essenceConcept, ancestor, contextHash)
|
|
343
|
+
aliasFactsKey = (aliasConcept, ancestor, contextHash)
|
|
344
|
+
if essenceFactsKey in self.esAlFacts and aliasFactsKey in self.esAlFacts:
|
|
345
|
+
for eF in self.esAlFacts[essenceFactsKey]:
|
|
346
|
+
for aF in self.esAlFacts[aliasFactsKey]:
|
|
347
|
+
essenceUnit = self.mapUnit.get(eF.unit,eF.unit)
|
|
348
|
+
aliasUnit = self.mapUnit.get(aF.unit,aF.unit)
|
|
349
|
+
if essenceUnit != aliasUnit:
|
|
350
|
+
yield Validation.inconsistency("xbrl.5.2.6.2.2:essenceAliasUnitsInconsistency",
|
|
351
|
+
_("Essence-Alias inconsistent units from %(essenceConcept)s to %(aliasConcept)s in link role %(linkrole)s context %(contextID)s"),
|
|
352
|
+
modelObject=(modelRel, eF, aF),
|
|
353
|
+
essenceConcept=essenceConcept.qname, aliasConcept=aliasConcept.qname,
|
|
354
|
+
linkrole=ELR,
|
|
355
|
+
linkroleDefinition=modelXbrl.roleTypeDefinition(ELR),
|
|
356
|
+
contextID=eF.context.id)
|
|
357
|
+
if not XbrlUtil.vEqual(eF, aF):
|
|
358
|
+
yield Validation.inconsistency("xbrl.5.2.6.2.2:essenceAliasUnitsInconsistency",
|
|
359
|
+
_("Essence-Alias inconsistent value from %(essenceConcept)s to %(aliasConcept)s in link role %(linkrole)s context %(contextID)s"),
|
|
360
|
+
modelObject=(modelRel, eF, aF),
|
|
361
|
+
essenceConcept=essenceConcept.qname, aliasConcept=aliasConcept.qname,
|
|
362
|
+
linkrole=ELR,
|
|
363
|
+
linkroleDefinition=modelXbrl.roleTypeDefinition(ELR),
|
|
364
|
+
contextID=eF.context.id)
|
|
365
|
+
elif arcrole == XbrlConst.requiresElement:
|
|
366
|
+
for modelRel in relsSet.modelRelationships:
|
|
367
|
+
sourceConcept = modelRel.fromModelObject
|
|
368
|
+
requiredConcept = modelRel.toModelObject
|
|
369
|
+
if sourceConcept in self.requiresElementFacts and \
|
|
370
|
+
not requiredConcept in self.requiresElementFacts:
|
|
371
|
+
yield Validation.inconsistency("xbrl.5.2.6.2.4:requiresElementInconsistency",
|
|
372
|
+
_("Requires-Element %(requiringConcept)s missing required fact for %(requiredConcept)s in link role %(linkrole)s"),
|
|
373
|
+
modelObject=sourceConcept,
|
|
374
|
+
requiringConcept=sourceConcept.qname, requiredConcept=requiredConcept.qname,
|
|
375
|
+
linkrole=ELR,
|
|
376
|
+
linkroleDefinition=modelXbrl.roleTypeDefinition(ELR))
|
|
353
377
|
modelXbrl.profileActivity("... find inconsistencies", minTimeToShow=1.0)
|
|
354
378
|
modelXbrl.profileActivity() # reset
|
|
355
379
|
|
|
@@ -419,11 +443,11 @@ class ValidateXbrlCalcs:
|
|
|
419
443
|
if concept in self.conceptsInRequiresElement:
|
|
420
444
|
self.requiresElementFacts[concept].append(f)
|
|
421
445
|
|
|
422
|
-
def consistentFactValueInterval(self, fList, truncate=False) -> tuple[decimal.Decimal | str, decimal.Decimal | str, bool, bool]:
|
|
446
|
+
def consistentFactValueInterval(self, fList, truncate=False) -> tuple[Validation | None, tuple[decimal.Decimal | str, decimal.Decimal | str, bool, bool]]:
|
|
423
447
|
_excessDigitFacts = []
|
|
424
448
|
if any(f.isNil for f in fList):
|
|
425
449
|
if all(f.isNil for f in fList):
|
|
426
|
-
return (NIL_FACT_SET,NIL_FACT_SET,True,True)
|
|
450
|
+
return None, (NIL_FACT_SET,NIL_FACT_SET,True,True)
|
|
427
451
|
_inConsistent = True # provide error message
|
|
428
452
|
else: # not all have same decimals
|
|
429
453
|
a = b = None
|
|
@@ -451,21 +475,21 @@ class ValidateXbrlCalcs:
|
|
|
451
475
|
inclB |= _inclB
|
|
452
476
|
_inConsistent = (a == b and not(inclA and inclB)) or (a > b)
|
|
453
477
|
if _excessDigitFacts:
|
|
454
|
-
|
|
478
|
+
return Validation.inconsistency("calc11e:excessDigits",
|
|
455
479
|
_("Calculations check stopped for excess digits in fact values %(element)s: %(values)s, %(contextIDs)s."),
|
|
456
480
|
modelObject=fList, element=_excessDigitFacts[0].qname,
|
|
457
481
|
contextIDs=", ".join(sorted(set(f.contextID for f in _excessDigitFacts))),
|
|
458
|
-
values=", ".join(strTruncate(f.value,64) for f in _excessDigitFacts)
|
|
459
|
-
|
|
482
|
+
values=", ".join(strTruncate(f.value,64) for f in _excessDigitFacts)
|
|
483
|
+
), (INCONSISTENT, INCONSISTENT,True,True)
|
|
460
484
|
if _inConsistent:
|
|
461
|
-
|
|
485
|
+
return Validation.inconsistency(
|
|
462
486
|
"calc11e:disallowedDuplicateFactsUsingTruncation" if self.calc11t else "oime:disallowedDuplicateFacts",
|
|
463
487
|
_("Calculations check stopped for duplicate fact values %(element)s: %(values)s, %(contextIDs)s."),
|
|
464
488
|
modelObject=fList, element=fList[0].qname,
|
|
465
489
|
contextIDs=", ".join(sorted(set(f.contextID for f in fList))),
|
|
466
|
-
values=", ".join(strTruncate(f.value,64) for f in fList)
|
|
467
|
-
|
|
468
|
-
return (a, b, inclA, inclB)
|
|
490
|
+
values=", ".join(strTruncate(f.value,64) for f in fList)
|
|
491
|
+
), (INCONSISTENT, INCONSISTENT,True,True)
|
|
492
|
+
return None, (a, b, inclA, inclB)
|
|
469
493
|
|
|
470
494
|
def roundFact(fact, inferDecimals=False, vDecimal=None):
|
|
471
495
|
if vDecimal is None:
|
arelle/WebCache.py
CHANGED
|
@@ -27,6 +27,7 @@ from urllib.parse import quote, unquote, urlsplit, urlunsplit
|
|
|
27
27
|
|
|
28
28
|
import certifi
|
|
29
29
|
import regex as re
|
|
30
|
+
import truststore
|
|
30
31
|
from filelock import FileLock, Timeout
|
|
31
32
|
|
|
32
33
|
from arelle.PythonUtil import isLegacyAbs
|
|
@@ -36,12 +37,6 @@ try:
|
|
|
36
37
|
except ImportError:
|
|
37
38
|
ssl = None
|
|
38
39
|
|
|
39
|
-
try:
|
|
40
|
-
import truststore
|
|
41
|
-
except ImportError:
|
|
42
|
-
# truststore requires Python > 3.9
|
|
43
|
-
truststore = None
|
|
44
|
-
|
|
45
40
|
from arelle.FileSource import SERVER_WEB_CACHE, archiveFilenameParts
|
|
46
41
|
from arelle.PluginManager import pluginClassMethods
|
|
47
42
|
from arelle.UrlUtil import isHttpUrl
|
|
@@ -282,8 +277,7 @@ class WebCache:
|
|
|
282
277
|
self.http_auth_handler = proxyhandlers.HTTPBasicAuthHandler()
|
|
283
278
|
proxyHandlers = [self.proxy_handler, self.proxy_auth_handler, self.http_auth_handler]
|
|
284
279
|
if ssl:
|
|
285
|
-
|
|
286
|
-
context = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT) if truststore else ssl.create_default_context()
|
|
280
|
+
context = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
287
281
|
# Include certifi certificates (Mozilla’s carefully curated
|
|
288
282
|
# collection) for systems with outdated certs.
|
|
289
283
|
context.load_verify_locations(cafile=certifi.where())
|
arelle/XbrlConst.py
CHANGED
|
@@ -143,6 +143,8 @@ qnXlResourceType = qname("{http://www.xbrl.org/2003/XLink}xl:resourceType")
|
|
|
143
143
|
qnXlArcType = qname("{http://www.xbrl.org/2003/XLink}xl:arcType")
|
|
144
144
|
xhtml = "http://www.w3.org/1999/xhtml"
|
|
145
145
|
qnXhtmlMeta = qname("{http://www.w3.org/1999/xhtml}meta")
|
|
146
|
+
qnXhtmlImg = qname("{http://www.w3.org/1999/xhtml}img")
|
|
147
|
+
qnXhtmlDel = qname("{http://www.w3.org/1999/xhtml}del")
|
|
146
148
|
ixbrl = "http://www.xbrl.org/2008/inlineXBRL"
|
|
147
149
|
ixbrl11 = "http://www.xbrl.org/2013/inlineXBRL"
|
|
148
150
|
ixbrlAll = {ixbrl, ixbrl11}
|