arelle-release 2.37.17__py3-none-any.whl → 2.37.19__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/CntlrWinMain.py +4 -1
- arelle/ModelValue.py +1 -0
- arelle/PythonUtil.py +132 -24
- arelle/ViewWinTree.py +15 -9
- arelle/_version.py +2 -2
- arelle/plugin/OimTaxonomy/ModelValueMore.py +15 -0
- arelle/plugin/OimTaxonomy/ValidateDTS.py +484 -0
- arelle/plugin/OimTaxonomy/ViewXbrlTxmyObj.py +240 -0
- arelle/plugin/OimTaxonomy/XbrlAbstract.py +16 -0
- arelle/plugin/OimTaxonomy/XbrlConcept.py +67 -0
- arelle/plugin/OimTaxonomy/XbrlConst.py +261 -0
- arelle/plugin/OimTaxonomy/XbrlCube.py +91 -0
- arelle/plugin/OimTaxonomy/XbrlDimension.py +38 -0
- arelle/plugin/OimTaxonomy/XbrlDts.py +152 -0
- arelle/plugin/OimTaxonomy/XbrlEntity.py +16 -0
- arelle/plugin/OimTaxonomy/XbrlGroup.py +22 -0
- arelle/plugin/OimTaxonomy/XbrlImportedTaxonomy.py +22 -0
- arelle/plugin/OimTaxonomy/XbrlLabel.py +31 -0
- arelle/plugin/OimTaxonomy/XbrlNetwork.py +100 -0
- arelle/plugin/OimTaxonomy/XbrlProperty.py +28 -0
- arelle/plugin/OimTaxonomy/XbrlReference.py +33 -0
- arelle/plugin/OimTaxonomy/XbrlReport.py +24 -0
- arelle/plugin/OimTaxonomy/XbrlTableTemplate.py +35 -0
- arelle/plugin/OimTaxonomy/XbrlTaxonomy.py +93 -0
- arelle/plugin/OimTaxonomy/XbrlTaxonomyObject.py +154 -0
- arelle/plugin/OimTaxonomy/XbrlTransform.py +17 -0
- arelle/plugin/OimTaxonomy/XbrlTypes.py +23 -0
- arelle/plugin/OimTaxonomy/XbrlUnit.py +17 -0
- arelle/plugin/OimTaxonomy/__init__.py +1038 -0
- arelle/plugin/OimTaxonomy/resources/iso4217.json +4479 -0
- arelle/plugin/OimTaxonomy/resources/oim-taxonomy-schema.json +935 -0
- arelle/plugin/OimTaxonomy/resources/ref.json +333 -0
- arelle/plugin/OimTaxonomy/resources/transform-types.json +2481 -0
- arelle/plugin/OimTaxonomy/resources/types.json +727 -0
- arelle/plugin/OimTaxonomy/resources/utr.json +3046 -0
- arelle/plugin/OimTaxonomy/resources/xbrlSpec.json +1082 -0
- arelle/plugin/saveOIMTaxonomy.py +311 -0
- arelle/plugin/validate/NL/PluginValidationDataExtension.py +36 -2
- arelle/plugin/validate/NL/__init__.py +3 -0
- arelle/plugin/validate/NL/rules/nl_kvk.py +84 -2
- {arelle_release-2.37.17.dist-info → arelle_release-2.37.19.dist-info}/METADATA +2 -1
- {arelle_release-2.37.17.dist-info → arelle_release-2.37.19.dist-info}/RECORD +54 -19
- tests/integration_tests/validation/README.md +2 -0
- tests/integration_tests/validation/conformance_suite_configurations/nl_inline_2024.py +15 -4
- tests/integration_tests/validation/run_conformance_suites.py +10 -1
- tests/integration_tests/validation/validation_util.py +10 -5
- tests/unit_tests/arelle/test_frozen_dict.py +176 -0
- tests/unit_tests/arelle/test_frozen_ordered_set.py +315 -0
- tests/unit_tests/arelle/test_import.py +31 -0
- tests/unit_tests/arelle/test_ordered_set.py +272 -0
- {arelle_release-2.37.17.dist-info → arelle_release-2.37.19.dist-info}/WHEEL +0 -0
- {arelle_release-2.37.17.dist-info → arelle_release-2.37.19.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.37.17.dist-info → arelle_release-2.37.19.dist-info}/licenses/LICENSE.md +0 -0
- {arelle_release-2.37.17.dist-info → arelle_release-2.37.19.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
'''
|
|
2
|
+
See COPYRIGHT.md for copyright information.
|
|
3
|
+
'''
|
|
4
|
+
|
|
5
|
+
import regex as re
|
|
6
|
+
from collections import defaultdict
|
|
7
|
+
from arelle.ModelValue import QName
|
|
8
|
+
from arelle.XmlValidate import languagePattern, validateValue as validateXmlValue
|
|
9
|
+
from arelle.PythonUtil import attrdict
|
|
10
|
+
from arelle.oim.Load import EMPTY_DICT, periodForms
|
|
11
|
+
from .XbrlAbstract import XbrlAbstract
|
|
12
|
+
from .XbrlConcept import XbrlConcept, XbrlDataType
|
|
13
|
+
from .XbrlCube import (XbrlCube, XbrlCubeType, baseCubeTypes, XbrlCubeDimension,
|
|
14
|
+
periodCoreDim, conceptCoreDim, entityCoreDim, unitCoreDim, languageCoreDim, coreDimensions,
|
|
15
|
+
conceptDomainRoot, entityDomainRoot, unitDomainRoot)
|
|
16
|
+
from .XbrlDimension import XbrlDimension, XbrlDomain, XbrlDomainRoot, XbrlMember
|
|
17
|
+
from .XbrlEntity import XbrlEntity
|
|
18
|
+
from .XbrlGroup import XbrlGroup, XbrlGroupContent
|
|
19
|
+
from .XbrlImportedTaxonomy import XbrlImportedTaxonomy
|
|
20
|
+
from .XbrlLabel import XbrlLabel
|
|
21
|
+
from .XbrlNetwork import XbrlNetwork, XbrlRelationship, XbrlRelationshipType
|
|
22
|
+
from .XbrlProperty import XbrlPropertyType
|
|
23
|
+
from .XbrlReference import XbrlReference
|
|
24
|
+
from .XbrlTableTemplate import XbrlTableTemplate
|
|
25
|
+
from .XbrlTaxonomy import XbrlTaxonomy, xbrlObjectTypes, xbrlObjectQNames
|
|
26
|
+
from .XbrlUnit import XbrlUnit
|
|
27
|
+
from .XbrlConst import qnXsQName, qnXsDateTime, qnXsDuration, objectsWithProperties
|
|
28
|
+
|
|
29
|
+
perCnstrtFmtStartEndPattern = re.compile(r".*@(start|end)")
|
|
30
|
+
|
|
31
|
+
def validateDTS(dts):
|
|
32
|
+
|
|
33
|
+
for txmy in dts.taxonomies.values():
|
|
34
|
+
validateTaxonomy(dts, txmy)
|
|
35
|
+
|
|
36
|
+
def objType(obj):
|
|
37
|
+
clsName = type(obj).__name__
|
|
38
|
+
if clsName.startswith("Xbrl"):
|
|
39
|
+
return clsName[4:]
|
|
40
|
+
return clsName
|
|
41
|
+
|
|
42
|
+
def validateValue(dts, obj, value, dataTypeQn, pathElt):
|
|
43
|
+
if isinstance(dataTypeQn, QName):
|
|
44
|
+
dataTypeObj = dts.namedObjects.get(dataTypeQn)
|
|
45
|
+
if not isinstance(dataTypeObj, XbrlDataType): # validity checked in owner object validations
|
|
46
|
+
return
|
|
47
|
+
dataTypeLn = dataTypeObj.xsBaseType(dts)
|
|
48
|
+
facets = dataTypeObj.xsFacets()
|
|
49
|
+
else: # string data type
|
|
50
|
+
dataTypeLn = dataTypeQn
|
|
51
|
+
facets = EMPTY_DICT
|
|
52
|
+
prototypeElt = attrdict(elementQname=dataTypeQn,
|
|
53
|
+
entryLoadingUrl=obj.entryLoadingUrl + pathElt)
|
|
54
|
+
validateXmlValue(dts, prototypeElt, None, dataTypeLn, value, False, False, facets)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def validateProperties(dts, oimFile, txmy, obj):
|
|
59
|
+
for i, propObj in enumerate(obj.properties):
|
|
60
|
+
propTypeQn = propObj.property
|
|
61
|
+
propTypeObj = dts.namedObjects.get(propTypeQn)
|
|
62
|
+
if not isinstance(propTypeObj, XbrlPropertyType):
|
|
63
|
+
dts.error("oime:invalidPropertyTypeObject",
|
|
64
|
+
_("%(parentObjName)s %(parentName)s property %(name)s has undefined dataType %(dataType)s"),
|
|
65
|
+
file=oimFile, parentObjName=objType(obj), parentName=getattr(obj,"name","(n/a)"),
|
|
66
|
+
name=propTypeQn, dataType=propTypeQn)
|
|
67
|
+
else: # have property type object
|
|
68
|
+
if propTypeObj.allowedObjects:
|
|
69
|
+
if xbrlObjectQNames.get(type(obj)) not in propTypeObj.allowedObjects:
|
|
70
|
+
dts.error("oime:disallowedObjectProperty",
|
|
71
|
+
_("%(parentObjName)s %(parentName)s property %(name)s not an allowed property type for the object."),
|
|
72
|
+
file=oimFile, parentObjName=objType(obj), parentName=getattr(obj,"name","(n/a)"),
|
|
73
|
+
name=propTypeQn)
|
|
74
|
+
validateValue(dts, obj, propObj.value, propTypeObj.dataType, f"/properties[{i}]")
|
|
75
|
+
|
|
76
|
+
def validateTaxonomy(dts, txmy):
|
|
77
|
+
oimFile = str(txmy.name)
|
|
78
|
+
|
|
79
|
+
def assertObjectType(obj, objType):
|
|
80
|
+
if not isinstance(obj, objType):
|
|
81
|
+
dts.error("oimte:invalidObjectType",
|
|
82
|
+
_("This %(thisType)s object was included where an %(expectedType)s object was expected."),
|
|
83
|
+
xbrlObject=obj, thisType=obj.__class__.__name__, expectedType=objType.__name__)
|
|
84
|
+
|
|
85
|
+
# Taxonomy object
|
|
86
|
+
assertObjectType(txmy, XbrlTaxonomy)
|
|
87
|
+
|
|
88
|
+
for impTxmyObj in txmy.importedTaxonomies:
|
|
89
|
+
assertObjectType(impTxmyObj, XbrlImportedTaxonomy)
|
|
90
|
+
for qnObjType in impTxmyObj.includeObjectTypes:
|
|
91
|
+
if qnObjType in xbrlObjectTypes:
|
|
92
|
+
if xbrlObjectTypes[qnObjType] == XbrlLabel:
|
|
93
|
+
dts.error("oimte:invalidObjectType",
|
|
94
|
+
_("The includeObjectTypes property MUST not include the label object."),
|
|
95
|
+
xbrlObject=qnObjType)
|
|
96
|
+
else:
|
|
97
|
+
dts.error("oimte:invalidObjectType",
|
|
98
|
+
_("The includeObjectTypes property MUST specify valid OIM object types, %(qname)s is not valid."),
|
|
99
|
+
xbrlObject=qnObjType, qname=qnObjType)
|
|
100
|
+
|
|
101
|
+
# Concept Objects
|
|
102
|
+
for cncpt in txmy.concepts:
|
|
103
|
+
assertObjectType(cncpt, XbrlConcept)
|
|
104
|
+
perType = cncpt.periodType
|
|
105
|
+
if perType not in ("instant", "duration"):
|
|
106
|
+
dts.error("oime:invalidPropertyValue",
|
|
107
|
+
_("Concept %(name)s has invalid period type %(perType)s"),
|
|
108
|
+
xbrlObject=cncpt, name=cncpt.name, perType=perType)
|
|
109
|
+
dataTypeQn = cncpt.dataType
|
|
110
|
+
if dataTypeQn not in dts.namedObjects or not isinstance(dts.namedObjects[dataTypeQn], XbrlDataType):
|
|
111
|
+
dts.error("oime:invalidDataTypeObject",
|
|
112
|
+
_("Concept %(name)s has invalid dataType %(dataType)s"),
|
|
113
|
+
xbrlObject=cncpt, name=cncpt.name, dataType=dataTypeQn)
|
|
114
|
+
enumDomQn = cncpt.enumerationDomain
|
|
115
|
+
if enumDomQn and (enumDomQn not in dts.namedObjects or not isinstance(dts.namedObjects[enumDomQn], XbrlDomain)):
|
|
116
|
+
dts.error("oime:invalidEnumerationDomainObject",
|
|
117
|
+
_("Concept %(name)s has invalid enumeration domain reference %(enumDomain)s"),
|
|
118
|
+
xbrlObject=cncpt, name=cncpt.name, enumDomain=enumDomQn)
|
|
119
|
+
validateProperties(dts, oimFile, txmy, cncpt)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# Cube Objects
|
|
123
|
+
for cubeObj in txmy.cubes:
|
|
124
|
+
assertObjectType(cubeObj, XbrlCube)
|
|
125
|
+
name = cubeObj.name
|
|
126
|
+
if cubeObj.cubeType and cubeObj.cubeType not in baseCubeTypes:
|
|
127
|
+
if not isinstance(dts.namedObjects.get(cubeObj.cubeType), XbrlCubeType):
|
|
128
|
+
dts.error("oimte:invalidPropertyValue",
|
|
129
|
+
_("The cube %(name)s cubeType %(qname)s must be a valid cube type."),
|
|
130
|
+
xbrlObject=cubeObj, name=name, qname=cubeObj.cubeType)
|
|
131
|
+
dimQnCounts = {}
|
|
132
|
+
for allowedCubeDimObj in cubeObj.cubeDimensions:
|
|
133
|
+
dimQn = allowedCubeDimObj.dimensionName
|
|
134
|
+
if dimQn not in coreDimensions and not isinstance(dts.namedObjects.get(dimQn), XbrlDimension):
|
|
135
|
+
dts.error("oimte:invalidTaxonomyDefinedDimension",
|
|
136
|
+
_("The allowedCubeDimensions property on cube %(name)s MUST resolve to a dimension object: %(dimension)s"),
|
|
137
|
+
xbrlObject=cubeObj, name=name, dimension=dimQn)
|
|
138
|
+
dimQnCounts[dimQn] = dimQnCounts.get(dimQn, 0) + 1
|
|
139
|
+
if any(c > 1 for c in dimQnCounts.values()):
|
|
140
|
+
dts.error("oimte:duplicateObjects",
|
|
141
|
+
_("The cubeDimensions property on cube %(name)s duplicate these dimension object(s): %(dimensions)s"),
|
|
142
|
+
xbrlObject=cubeObj, name=name, dimensions=", ".join(str(qn) for qn, ct in dimQnCounts.items if ct > 1))
|
|
143
|
+
for ntwrkQn in cubeObj.cubeNetworks:
|
|
144
|
+
if not isinstance(dts.namedObjects.get(ntwrkQn), XbrlNetwork):
|
|
145
|
+
dts.error("oimte:invalidCubeNetwork",
|
|
146
|
+
_("The cubeNetworks property on cube %(name)s MUST resolve %(qname)s to a network object."),
|
|
147
|
+
xbrlObject=cubeObj, name=name, qname=ntwrkQn)
|
|
148
|
+
for exclCubeQn in cubeObj.excludeCubes:
|
|
149
|
+
if exclCubeQn == cubeObj.name:
|
|
150
|
+
dts.error("oimte:invalidPropertyValue",
|
|
151
|
+
_("The cube %(name)s must not be defined in the excludeCubes property of itself."),
|
|
152
|
+
xbrlObject=cubeObj, name=name)
|
|
153
|
+
if not isinstance(dts.namedObjects.get(exclCubeQn), XbrlCube):
|
|
154
|
+
dts.error("oimte:missingQNameReference",
|
|
155
|
+
_("The excludeCubes property on cube %(name)s MUST resolve %(qname)s to a cube object."),
|
|
156
|
+
xbrlObject=cubeObj, name=name, qname=exclCubeQn)
|
|
157
|
+
validateProperties(dts, oimFile, txmy, cubeObj)
|
|
158
|
+
unitDataTypeQNs = set()
|
|
159
|
+
cncptDataTypeQNs = set()
|
|
160
|
+
for iCubeDim, cubeDimObj in enumerate(cubeObj.cubeDimensions):
|
|
161
|
+
assertObjectType(cubeDimObj, XbrlCubeDimension)
|
|
162
|
+
dimName = cubeDimObj.dimensionName
|
|
163
|
+
if cubeDimObj.domainSort not in (None, "asc", "desc"):
|
|
164
|
+
dts.error("oimte:invalidCubeDimensionProperty",
|
|
165
|
+
_("Cube %(name)s domainSort property MUST be asc or desc, not %(domainSort)s."),
|
|
166
|
+
xbrlObject=cubeObj, name=name, domainSort=cubeDimObj.domainSort)
|
|
167
|
+
if cubeDimObj.periodConstraints and dimName != periodCoreDim:
|
|
168
|
+
dts.error("oimte:invalidDimensionConstraint",
|
|
169
|
+
_("Cube %(name)s periodConstraints property MUST only be used where the dimensionName property has a QName value of xbrl:period, not %(qname)s."),
|
|
170
|
+
xbrlObject=cubeObj, name=name, qname=dimName)
|
|
171
|
+
if dimName == conceptCoreDim and isinstance(dts.namedObjects.get(cubeDimObj.domainName), XbrlDomain):
|
|
172
|
+
for relObj in dts.namedObjects[cubeDimObj.domainName].relationships:
|
|
173
|
+
if not isinstance(dts.namedObjects.get(relObj.source,None), (XbrlConcept, XbrlAbstract)) and relObj.source != conceptDomainRoot:
|
|
174
|
+
dts.error("oimte:invalidRelationshipSource",
|
|
175
|
+
_("Cube %(name)s conceptConstraints domain relationships must be from concepts, source: %(source)s."),
|
|
176
|
+
xbrlObject=(cubeObj,cubeDimObj,relObj), name=name, qname=dimName, source=relObj.source)
|
|
177
|
+
if isinstance(dts.namedObjects.get(relObj.target,None), XbrlConcept):
|
|
178
|
+
cncptDataTypeQNs.add(dts.namedObjects[relObj.target].dataType)
|
|
179
|
+
elif not isinstance(dts.namedObjects.get(relObj.target,None), XbrlAbstract):
|
|
180
|
+
dts.error("oimte:invalidRelationshipTarget",
|
|
181
|
+
_("Cube %(name)s conceptConstraints domain relationships must be to concepts, target: %(target)s."),
|
|
182
|
+
xbrlObject=(cubeObj,cubeDimObj,relObj), name=name, qname=dimName, target=relObj.target)
|
|
183
|
+
if dimName == entityCoreDim and isinstance(dts.namedObjects.get(cubeDimObj.domainName), XbrlDomain):
|
|
184
|
+
for relObj in dts.namedObjects[cubeDimObj.domainName].relationships:
|
|
185
|
+
if not isinstance(dts.namedObjects.get(relObj.source,None), XbrlEntity) and relObj.source != entityDomainRoot:
|
|
186
|
+
dts.error("oimte:invalidRelationshipSource",
|
|
187
|
+
_("Cube %(name)s entityConstraints domain relationships must be from entities, source: %(source)s."),
|
|
188
|
+
xbrlObject=(cubeObj,cubeDimObj,relObj), name=name, qname=dimName, source=relObj.source)
|
|
189
|
+
if not isinstance(dts.namedObjects.get(relObj.target,None), XbrlEntity):
|
|
190
|
+
dts.error("oimte:invalidRelationshipTarget",
|
|
191
|
+
_("Cube %(name)s entityConstraints domain relationships must be to entities, target: %(target)s."),
|
|
192
|
+
xbrlObject=(cubeObj,cubeDimObj,relObj), name=name, qname=dimName, target=relObj.target)
|
|
193
|
+
if dimName == unitCoreDim and isinstance(dts.namedObjects.get(cubeDimObj.domainName), XbrlDomain):
|
|
194
|
+
for relObj in dts.namedObjects[cubeDimObj.domainName].relationships:
|
|
195
|
+
if not isinstance(dts.namedObjects.get(relObj.source,None), XbrlUnit) and relObj.source != unitDomainRoot:
|
|
196
|
+
dts.error("oimte:invalidRelationshipSource",
|
|
197
|
+
_("Cube %(name)s unitConstraints domain relationships must be from units, source: %(source)s."),
|
|
198
|
+
xbrlObject=(cubeObj,cubeDimObj,relObj), name=name, qname=dimName, source=relObj.source)
|
|
199
|
+
if not isinstance(dts.namedObjects.get(relObj.target,None), XbrlUnit):
|
|
200
|
+
dts.error("oimte:invalidRelationshipTarget",
|
|
201
|
+
_("Cube %(name)s unitConstraints domain relationships must be to units, target: %(target)s."),
|
|
202
|
+
xbrlObject=(cubeObj,cubeDimObj,relObj), name=name, qname=dimName, target=relObj.target)
|
|
203
|
+
if dimName not in coreDimensions and isinstance(dts.namedObjects.get(dimName), XbrlDimension):
|
|
204
|
+
dimObj = dts.namedObjects[dimName]
|
|
205
|
+
if dimObj.domainDataType: # typed
|
|
206
|
+
if dimObj.domainRoot:
|
|
207
|
+
dts.error("oimte:invalidQNameReference",
|
|
208
|
+
_("Cube %(name)s typed dimension %(qname)s must not specify a domain root."),
|
|
209
|
+
xbrlObject=(cubeObj,cubeDimObj,dimObj), name=name, qname=dimName)
|
|
210
|
+
else: # explicit dim
|
|
211
|
+
domObj = dts.namedObjects.get(cubeDimObj.domainName)
|
|
212
|
+
if domObj:
|
|
213
|
+
for relObj in domObj.relationships:
|
|
214
|
+
if not isinstance(dts.namedObjects.get(getattr(relObj, "target", None),None), XbrlMember):
|
|
215
|
+
dts.error("oimte:invalidRelationshipTarget",
|
|
216
|
+
_("Cube %(name)s explicit dimension domain relationships must be to members."),
|
|
217
|
+
xbrlObject=(cubeObj,dimObj,relObj), name=name, qname=dimName)
|
|
218
|
+
if cubeDimObj.domainName and dimName in (periodCoreDim, languageCoreDim):
|
|
219
|
+
dts.error("oimte:invalidCubeDimensionProperty",
|
|
220
|
+
_("Cube %(name)s domainName property MUST NOT be used where the dimensionName property has a QName value %(qname)s."),
|
|
221
|
+
xbrlObject=cubeObj, name=name, qname=dimName)
|
|
222
|
+
|
|
223
|
+
if dimName == periodCoreDim:
|
|
224
|
+
for iPerConst, perConstObj in enumerate(cubeDimObj.periodConstraints):
|
|
225
|
+
if perConstObj.periodType not in ("instant", "duration"):
|
|
226
|
+
dts.error("oimte:invalidPeriodRepresentation",
|
|
227
|
+
_("Cube %(name)s period constraint periodType property MUST be \"instant\" or \"duration\"."),
|
|
228
|
+
xbrlObject=(cubeObj,cubeDimObj), name=name)
|
|
229
|
+
if perConstObj.timeSpan:
|
|
230
|
+
if perConstObj.endDate and perConstObj.startDate:
|
|
231
|
+
dts.error("oimte:invalidPeriodRepresentation",
|
|
232
|
+
_("Cube %(name)s period constraint timeSpan property MUST NOT be used with both the endDate and startDate properties."),
|
|
233
|
+
xbrlObject=(cubeObj,cubeDimObj), name=name)
|
|
234
|
+
validateValue(dts, cubeObj, perConstObj.timeSpan, "duration" ,f"/cubeDimensions[{iCubeDim}]/periodConstraints[{iPerConst}]/timeSpan")
|
|
235
|
+
if perConstObj.periodFormat:
|
|
236
|
+
if perConstObj.timeSpan or perConstObj.endDate or perConstObj.startDate:
|
|
237
|
+
dts.error("oimte:invalidPeriodRepresentation",
|
|
238
|
+
_("Cube %(name)s period constraint periodFormat property MUST NOT be used with the timeSpan, endDate or startDate properties."),
|
|
239
|
+
xbrlObject=(cubeObj,cubeDimObj), name=name)
|
|
240
|
+
if not any(perFormMatch.match(perConstObj.periodFormat) for _perType, perFormMatch in periodForms):
|
|
241
|
+
dts.error("oimte:invalidPeriodRepresentation",
|
|
242
|
+
_("Cube %(name)s periodConstraint[%(perConstNbr)s] periodFormat property, %(periodFormat)s, MUST be a valid period format per xbrl-csv specification."),
|
|
243
|
+
xbrlObject=(cubeObj,cubeDimObj), name=name, perConstNbr=iPerConst, periodFormat=perConstObj.periodFormat)
|
|
244
|
+
if perConstObj.periodType != "instant" and perConstObj.periodFormat and perCnstrtFmtStartEndPattern.match(perConstObj.periodFormat):
|
|
245
|
+
dts.error("oimte:invalidPeriodRepresentation",
|
|
246
|
+
_("Cube %(name)s period constraint periodFormat the suffix of @start or @end MUST only be used with periodType of instant."),
|
|
247
|
+
xbrlObject=(cubeObj,cubeDimObj), name=name)
|
|
248
|
+
if perConstObj.periodType == "instant" and (perConstObj.timeSpan or perConstObj.startDate):
|
|
249
|
+
dts.error("oimte:invalidPeriodRepresentation",
|
|
250
|
+
_("Cube %(name)s period constraint periodType instant MUST NOT define timeSpan or startDate."),
|
|
251
|
+
xbrlObject=(cubeObj,cubeDimObj), name=name)
|
|
252
|
+
for dtResProp in ("monthDay", "endDate", "startDate", "onOrAfter", "onOrBefore"):
|
|
253
|
+
dtResObj = getattr(perConstObj, dtResProp, None)
|
|
254
|
+
if dtResObj is not None:
|
|
255
|
+
if dtResObj.conceptName:
|
|
256
|
+
cncpt = dts.namedObjects.get(dtResObj.conceptName)
|
|
257
|
+
if not cncpt or not isinstance(dts.namedObjects.get(cncpt.dataType), XbrlDataType) or dts.namedObjects[cncpt.dataType].baseType != qnXsDateTime:
|
|
258
|
+
dts.error("oimte:invalidPeriodRepresentation",
|
|
259
|
+
_("Cube %(name)s period constraint concept %(qname)s base type MUST be a date."),
|
|
260
|
+
xbrlObject=(cubeObj,cubeDimObj), name=name, qname=dtResObj.conceptName)
|
|
261
|
+
if dtResObj.context:
|
|
262
|
+
cncpt = dts.namedObjects.get(dtResObj.context)
|
|
263
|
+
if not cncpt or not isinstance(cncpt, XbrlConcept) or (dtResObj.context.atSuffix not in ("start","end")):
|
|
264
|
+
dts.error("oimte:invalidPeriodRepresentation",
|
|
265
|
+
_("Cube %(name)s period constraint concept %(qname)s base type MUST be a concept and any suffix MUST be start or end."),
|
|
266
|
+
xbrlObject=(cubeObj,cubeDimObj), name=name, qname=dtResObj.context)
|
|
267
|
+
if dtResObj.timeShift:
|
|
268
|
+
if dtResObj.value or (dtResObj.conceptName and dtResObj.context):
|
|
269
|
+
dts.error("oimte:invalidPeriodRepresentation",
|
|
270
|
+
_("Cube %(name)s period constraint concept %(qname)s timeShift MUST be used with only one of the properties name, or context."),
|
|
271
|
+
xbrlObject=(cubeObj,cubeDimObj), name=name, qname=dtResObj.context)
|
|
272
|
+
validateValue(dts, cubeObj, dtResObj.timeShift, "duration" ,f"/cubeDimensions[{iCubeDim}]/periodConstraints[{iPerConst}]/{dtResProp}/timeShift")
|
|
273
|
+
if dtResObj.value:
|
|
274
|
+
validateValue(dts, cubeObj, dtResObj.value, "XBRLI_DATEUNION", f"/cubeDimensions[{iCubeDim}]/periodConstraints[{iPerConst}]/{dtResProp}/value")
|
|
275
|
+
else:
|
|
276
|
+
if cubeDimObj.periodConstraints:
|
|
277
|
+
dts.error("oimte:invalidDimensionConstraint",
|
|
278
|
+
_("Cube %(name)s periodConstraints property MUST only be used where the dimensionName property has a QName value of xbrl:period, not %(qname)s."),
|
|
279
|
+
xbrlObject=cubeObj, name=name, qname=dimName)
|
|
280
|
+
for unitDataTypeQN in unitDataTypeQNs:
|
|
281
|
+
if unitDataTypeQN not in cncptDataTypeQNs:
|
|
282
|
+
dts.error("oimte:invalidDataTypeObject",
|
|
283
|
+
_("Cube %(name)s unitConstraints data Type %(dataType)s MUST have at least one associated concept object on the concept core dimension with the same datatype as the unit object."),
|
|
284
|
+
xbrlObject=(cubeObj,cubeDimObj), name=name, dataType=unitDataTypeQN)
|
|
285
|
+
|
|
286
|
+
# DataType Objects
|
|
287
|
+
for dtObj in txmy.dataTypes:
|
|
288
|
+
assertObjectType(dtObj, XbrlDataType)
|
|
289
|
+
btQn = dtObj.baseType
|
|
290
|
+
if btQn and btQn.namespaceURI != "http://www.w3.org/2001/XMLSchema" and not isinstance(dts.namedObjects.get(btQn), XbrlDataType):
|
|
291
|
+
dts.error("oimte:invalidPropertyValue",
|
|
292
|
+
_("The dataType object %(name)s MUST define a valid baseType which must be a dataType object in the dts"),
|
|
293
|
+
xbrlObject=dtObj, name=dt.name)
|
|
294
|
+
for unitTpObj in dtObj.unitTypes:
|
|
295
|
+
assertObjectType(utObj, XbrlUnitType)
|
|
296
|
+
for utProp in ("dataTypeNumerator", "dataTypeDenominator", "dataTypeMutiplier"):
|
|
297
|
+
utPropQn = getattr(utObj, utProp)
|
|
298
|
+
if utPropQn and not isinstance(dts.namedObjects.get(utPropQn), XbrlDataType):
|
|
299
|
+
dts.error("oimte:invalidPropertyValue",
|
|
300
|
+
_("The dataType object unitType %(name)s MUST define a valid dataType object in the dts"),
|
|
301
|
+
xbrlObject=dtObj, name=dt.name)
|
|
302
|
+
|
|
303
|
+
# Dimension Objects
|
|
304
|
+
for dimObj in txmy.dimensions:
|
|
305
|
+
assertObjectType(dimObj, XbrlDimension)
|
|
306
|
+
for cubeTypeQn in dimObj.cubeTypes:
|
|
307
|
+
if not isinstance(dts.namedObjects.get(cubeTypeQn), XbrlCubeType):
|
|
308
|
+
dts.error("oimte:invalidPropertyValue",
|
|
309
|
+
_("The dimension cubeType QName %(name)s MUST be a valid cubeType object in the dts"),
|
|
310
|
+
xbrlObject=dimObj, name=cubeTypeQn)
|
|
311
|
+
if dimObj.domainDataType and not isinstance(dts.namedObjects.get(dimObj.domainDataType), XbrlDataType):
|
|
312
|
+
dts.error("oimte:invalidPropertyValue",
|
|
313
|
+
_("The dimension domain dataType object QName %(name)s MUST be a valid dataType object in the dts"),
|
|
314
|
+
xbrlObject=dimObj, name=dimObj.domainDataType)
|
|
315
|
+
if dimObj.domainRoot and not isinstance(dts.namedObjects.get(dimObj.domainRoot), XbrlDomainRoot):
|
|
316
|
+
dts.error("oimte:invalidPropertyValue",
|
|
317
|
+
_("The dimension domainRoot object QName %(name)s MUST be a valid domainRoot object in the dts"),
|
|
318
|
+
xbrlObject=dimObj, name=dimObj.domainRoot)
|
|
319
|
+
|
|
320
|
+
# Domain Objects
|
|
321
|
+
for domObj in txmy.domains:
|
|
322
|
+
assertObjectType(domObj, XbrlDomain)
|
|
323
|
+
if domObj.extendTargetName:
|
|
324
|
+
if domObj.name:
|
|
325
|
+
dts.error("oimte:invalidObjectProperty",
|
|
326
|
+
_("The domain %(name)s MUST have only a name or an extendTargetName, not both."),
|
|
327
|
+
xbrlObject=domObj, name=domObj.name)
|
|
328
|
+
elif not isinstance(dts.namedObjects.get(domObj.extendTargetName), XbrlDomain):
|
|
329
|
+
dts.error("oimte:missingTargetObject",
|
|
330
|
+
_("The domain %(name)s MUST be a valid domain object in the dts"),
|
|
331
|
+
xbrlObject=domObj, name=domObj.name or domObj.extendTargetName)
|
|
332
|
+
elif not domObj.name:
|
|
333
|
+
dts.error("oimte:missingRequiredProperty",
|
|
334
|
+
_("The domain object MUST have either a name or an extendTargetName, not neither."),
|
|
335
|
+
xbrlObject=domObj)
|
|
336
|
+
|
|
337
|
+
if not domObj.extendTargetName and not isinstance(dts.namedObjects.get(domObj.root), XbrlDomainRoot):
|
|
338
|
+
dts.error("oimte:missingTargetObject",
|
|
339
|
+
_("The domain %(name)s root %(qname)s MUST be a valid domainRoot object in the dts"),
|
|
340
|
+
xbrlObject=domObj, name=domObj.name, qname=domObj.root)
|
|
341
|
+
for relObj in domObj.relationships:
|
|
342
|
+
assertObjectType(relObj, XbrlRelationship)
|
|
343
|
+
if isinstance(dts.namedObjects.get(relObj.target), (XbrlDomain, XbrlDomainRoot)):
|
|
344
|
+
dts.error("oimte:invalidFactMember",
|
|
345
|
+
_("The domain %(name)s relationship target %(qname)s MUST NOT be a domain or domainRoot object."),
|
|
346
|
+
xbrlObject=domObj, name=domObj.name, qname=relObj.target)
|
|
347
|
+
validateProperties(dts, oimFile, txmy, domObj)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# DomainRoot Objects
|
|
351
|
+
for domRtObj in txmy.domainRoots:
|
|
352
|
+
assertObjectType(domRtObj, XbrlDomainRoot)
|
|
353
|
+
validateProperties(dts, oimFile, txmy, domRtObj)
|
|
354
|
+
|
|
355
|
+
# Entity Objects
|
|
356
|
+
for entityObj in txmy.entities:
|
|
357
|
+
assertObjectType(entityObj, XbrlEntity)
|
|
358
|
+
validateProperties(dts, oimFile, txmy, entityObj)
|
|
359
|
+
|
|
360
|
+
# GroupContent Objects
|
|
361
|
+
for grpCntObj in txmy.groupContents:
|
|
362
|
+
assertObjectType(grpCntObj, XbrlGroupContent)
|
|
363
|
+
grpQn = grpCntObj.groupName
|
|
364
|
+
if grpQn not in dts.namedObjects or type(dts.namedObjects[grpQn]) != XbrlGroup:
|
|
365
|
+
dts.error("oimte:invalidGroupObject",
|
|
366
|
+
_("The groupContent object groupName QName %(name)s MUST be a valid group object in the dts"),
|
|
367
|
+
xbrlObject=grpCntObj, name=grpQn)
|
|
368
|
+
for relName in grpCntObj.relatedNames:
|
|
369
|
+
if relName not in dts.namedObjects or not isinstance(dts.namedObjects.get(relName), (XbrlNetwork, XbrlCube, XbrlTableTemplate)):
|
|
370
|
+
dts.error("oimte:invalidGroupObject",
|
|
371
|
+
_("The groupContent object %(name)s relatedName %(relName)s MUST only include QNames associated with network objects, cube objects or table template objects."),
|
|
372
|
+
xbrlObject=grpCntObj, name=grpQn, relName=relName)
|
|
373
|
+
|
|
374
|
+
# Label Objects
|
|
375
|
+
for labelObj in txmy.labels:
|
|
376
|
+
assertObjectType(labelObj, XbrlLabel)
|
|
377
|
+
relatedName = labelObj.relatedName
|
|
378
|
+
lang = labelObj.language
|
|
379
|
+
if not languagePattern.match(lang):
|
|
380
|
+
dts.error("oime:invalidLanguage",
|
|
381
|
+
_("Label %(relatedName)s has invalid language %(lang)s"),
|
|
382
|
+
xbrlObject=labelObj, relatedName=relatedName, lang=lang)
|
|
383
|
+
if relatedName not in dts.namedObjects:
|
|
384
|
+
dts.error("oime:unresolvedRelatedName",
|
|
385
|
+
_("Label has invalid related object %(relatedName)s"),
|
|
386
|
+
xbrlObject=labelObj, relatedName=relatedName)
|
|
387
|
+
validateProperties(dts, oimFile, txmy, labelObj)
|
|
388
|
+
|
|
389
|
+
# Network Objects
|
|
390
|
+
for ntwkObj in txmy.networks:
|
|
391
|
+
assertObjectType(ntwkObj, XbrlNetwork)
|
|
392
|
+
if ntwkObj.extendTargetName:
|
|
393
|
+
if ntwkObj.name:
|
|
394
|
+
dts.error("oimte:invalidObjectProperty",
|
|
395
|
+
_("The network %(name)s MUST have only a name or an extendTargetName, not both."),
|
|
396
|
+
xbrlObject=ntwkObj, name=ntwkObj.name)
|
|
397
|
+
elif not isinstance(dts.namedObjects.get(ntwkObj.extendTargetName), XbrlNetwork):
|
|
398
|
+
dts.error("oimte:missingTargetObject",
|
|
399
|
+
_("The network extendTargetName %(name)s MUST be a valid network object in the dts"),
|
|
400
|
+
xbrlObject=ntwkObj, name=ntwkObj.name or ntwkObj.extendTargetName)
|
|
401
|
+
elif not ntwkObj.name:
|
|
402
|
+
dts.error("oimte:missingRequiredProperty",
|
|
403
|
+
_("The network object MUST have either a name or an extendTargetName, not neither."),
|
|
404
|
+
xbrlObject=ntwkObj)
|
|
405
|
+
|
|
406
|
+
for rootQn in ntwkObj.roots:
|
|
407
|
+
if rootQn not in dts.namedObjects:
|
|
408
|
+
dts.error("oimte:missingTargetObject",
|
|
409
|
+
_("The network %(name)s root %(qname)s MUST be a valid object in the dts"),
|
|
410
|
+
xbrlObject=ntwkObj, name=ntwkObj.name, qname=rootQn)
|
|
411
|
+
for i, relObj in enumerate(domObj.relationships):
|
|
412
|
+
assertObjectType(relObj, XbrlRelationship)
|
|
413
|
+
if relObj.source not in dts.namedObjects or relObj.target not in dts.namedObjects:
|
|
414
|
+
dts.error("oimte:missingTargetObject",
|
|
415
|
+
_("The network %(name)s relationship[%(nbr)s] source, %(source)s, and target, %(target)s, MUST be objects in the DTS."),
|
|
416
|
+
xbrlObject=domObj, name=ntwkObj.name, nbr=i, source=relObj.source, target=relObj.target)
|
|
417
|
+
validateProperties(dts, oimFile, txmy, relObj)
|
|
418
|
+
validateProperties(dts, oimFile, txmy, ntwkObj)
|
|
419
|
+
|
|
420
|
+
# PropertyType Objects
|
|
421
|
+
for propTpObj in txmy.propertyTypes:
|
|
422
|
+
assertObjectType(propTpObj, XbrlPropertyType)
|
|
423
|
+
if not isinstance(dts.namedObjects.get(propTpObj.dataType), XbrlDataType):
|
|
424
|
+
dts.error("oimte:invalidDataTypeObject",
|
|
425
|
+
_("The propertyType %(name)s dataType %(qname)s MUST be a valid dataType object in the dts"),
|
|
426
|
+
xbrlObject=ntwkObj, name=propTpObj.name, qname=propTpObj.dataType)
|
|
427
|
+
elif propTpObj.enumerationDomain and dts.namedObjects[propTpObj.dataType.baseType] != qnXsQName:
|
|
428
|
+
dts.error("oimte:invalidDataTypeObject",
|
|
429
|
+
_("The propertyType %(name)s dataType %(qname)s MUST be a valid dataType object in the dts"),
|
|
430
|
+
xbrlObject=ntwkObj, name=propTpObj.name, qname=propTpObj.dataType)
|
|
431
|
+
for allowedObjQn in propTpObj.allowedObjects:
|
|
432
|
+
if allowedObjQn not in objectsWithProperties:
|
|
433
|
+
dts.error("oime:invalidAllowedObject",
|
|
434
|
+
_("The property %(name)s has an invalid allowed object %(allowedObj)s"),
|
|
435
|
+
file=oimFile, name=propTpObj.name, allowedObj=allowedObjQn)
|
|
436
|
+
|
|
437
|
+
# RelationshipType Objects
|
|
438
|
+
for relTpObj in txmy.relationshipTypes:
|
|
439
|
+
assertObjectType(relTpObj, XbrlRelationshipType)
|
|
440
|
+
|
|
441
|
+
# Reference Objects
|
|
442
|
+
refsWithInvalidLang = defaultdict(list)
|
|
443
|
+
refsWithInvalidRelName = []
|
|
444
|
+
refInvalidNames = []
|
|
445
|
+
for refObj in txmy.references:
|
|
446
|
+
assertObjectType(refObj, XbrlReference)
|
|
447
|
+
name = refObj.name
|
|
448
|
+
lang = refObj.language
|
|
449
|
+
if lang is not None and not languagePattern.match(lang):
|
|
450
|
+
refsWithInvalidLang[lang].append(refObj)
|
|
451
|
+
for relName in refObj.relatedNames:
|
|
452
|
+
if relName not in dts.namedObjects:
|
|
453
|
+
refsWithInvalidRelName.append(refObj)
|
|
454
|
+
refInvalidNames.append(relName)
|
|
455
|
+
validateProperties(dts, oimFile, txmy, refObj)
|
|
456
|
+
if refsWithInvalidRelName:
|
|
457
|
+
dts.warning("oime:unresolvedRelatedNameWarning",
|
|
458
|
+
_("References have invalid related object names %(relNames)s"),
|
|
459
|
+
xbrlObject=refsWithInvalidRelName, name=name, relNames=", ".join(str(qn) for qn in refInvalidNames))
|
|
460
|
+
for lang, refObjs in refsWithInvalidLang:
|
|
461
|
+
dts.warning("oime:invalidLanguageWarning",
|
|
462
|
+
_("Reference object(s) have invalid language %(lang)s"),
|
|
463
|
+
xbrlObject=refObjs, lang=lang)
|
|
464
|
+
del refsWithInvalidLang, refsWithInvalidRelName, refInvalidNames # dereference
|
|
465
|
+
|
|
466
|
+
# Unit Objects
|
|
467
|
+
for unitObj in txmy.units:
|
|
468
|
+
assertObjectType(unitObj, XbrlUnit)
|
|
469
|
+
usedDataTypes = set()
|
|
470
|
+
|
|
471
|
+
for dtProp in ("dataType", "dataTypeNumerator", "aTypeDenominator"):
|
|
472
|
+
dtQn = getattr(unitObj, dtProp, None)
|
|
473
|
+
if dtQn:
|
|
474
|
+
if not isinstance(dts.namedObjects.get(dtQn), XbrlDataType):
|
|
475
|
+
dts.error("oimte:invalidUnitDataType",
|
|
476
|
+
_("The unit %(name)s %(property)s %(qname)s MUST be a dataType object."),
|
|
477
|
+
xbrlObject=unitObj, name=unitObj.name, property=dtProp, qname=dtQn)
|
|
478
|
+
else:
|
|
479
|
+
if dtQn in usedDataTypes:
|
|
480
|
+
dts.error("oimte:invalidUnitDataType",
|
|
481
|
+
_("The unit %(name)s %(qname)s MUST only be used once in the unit object."),
|
|
482
|
+
xbrlObject=unitObj, name=unitObj.name, qname=dtQn)
|
|
483
|
+
usedDataTypes.add(dtQn)
|
|
484
|
+
del usedDataTypes
|