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.

Files changed (54) hide show
  1. arelle/CntlrWinMain.py +4 -1
  2. arelle/ModelValue.py +1 -0
  3. arelle/PythonUtil.py +132 -24
  4. arelle/ViewWinTree.py +15 -9
  5. arelle/_version.py +2 -2
  6. arelle/plugin/OimTaxonomy/ModelValueMore.py +15 -0
  7. arelle/plugin/OimTaxonomy/ValidateDTS.py +484 -0
  8. arelle/plugin/OimTaxonomy/ViewXbrlTxmyObj.py +240 -0
  9. arelle/plugin/OimTaxonomy/XbrlAbstract.py +16 -0
  10. arelle/plugin/OimTaxonomy/XbrlConcept.py +67 -0
  11. arelle/plugin/OimTaxonomy/XbrlConst.py +261 -0
  12. arelle/plugin/OimTaxonomy/XbrlCube.py +91 -0
  13. arelle/plugin/OimTaxonomy/XbrlDimension.py +38 -0
  14. arelle/plugin/OimTaxonomy/XbrlDts.py +152 -0
  15. arelle/plugin/OimTaxonomy/XbrlEntity.py +16 -0
  16. arelle/plugin/OimTaxonomy/XbrlGroup.py +22 -0
  17. arelle/plugin/OimTaxonomy/XbrlImportedTaxonomy.py +22 -0
  18. arelle/plugin/OimTaxonomy/XbrlLabel.py +31 -0
  19. arelle/plugin/OimTaxonomy/XbrlNetwork.py +100 -0
  20. arelle/plugin/OimTaxonomy/XbrlProperty.py +28 -0
  21. arelle/plugin/OimTaxonomy/XbrlReference.py +33 -0
  22. arelle/plugin/OimTaxonomy/XbrlReport.py +24 -0
  23. arelle/plugin/OimTaxonomy/XbrlTableTemplate.py +35 -0
  24. arelle/plugin/OimTaxonomy/XbrlTaxonomy.py +93 -0
  25. arelle/plugin/OimTaxonomy/XbrlTaxonomyObject.py +154 -0
  26. arelle/plugin/OimTaxonomy/XbrlTransform.py +17 -0
  27. arelle/plugin/OimTaxonomy/XbrlTypes.py +23 -0
  28. arelle/plugin/OimTaxonomy/XbrlUnit.py +17 -0
  29. arelle/plugin/OimTaxonomy/__init__.py +1038 -0
  30. arelle/plugin/OimTaxonomy/resources/iso4217.json +4479 -0
  31. arelle/plugin/OimTaxonomy/resources/oim-taxonomy-schema.json +935 -0
  32. arelle/plugin/OimTaxonomy/resources/ref.json +333 -0
  33. arelle/plugin/OimTaxonomy/resources/transform-types.json +2481 -0
  34. arelle/plugin/OimTaxonomy/resources/types.json +727 -0
  35. arelle/plugin/OimTaxonomy/resources/utr.json +3046 -0
  36. arelle/plugin/OimTaxonomy/resources/xbrlSpec.json +1082 -0
  37. arelle/plugin/saveOIMTaxonomy.py +311 -0
  38. arelle/plugin/validate/NL/PluginValidationDataExtension.py +36 -2
  39. arelle/plugin/validate/NL/__init__.py +3 -0
  40. arelle/plugin/validate/NL/rules/nl_kvk.py +84 -2
  41. {arelle_release-2.37.17.dist-info → arelle_release-2.37.19.dist-info}/METADATA +2 -1
  42. {arelle_release-2.37.17.dist-info → arelle_release-2.37.19.dist-info}/RECORD +54 -19
  43. tests/integration_tests/validation/README.md +2 -0
  44. tests/integration_tests/validation/conformance_suite_configurations/nl_inline_2024.py +15 -4
  45. tests/integration_tests/validation/run_conformance_suites.py +10 -1
  46. tests/integration_tests/validation/validation_util.py +10 -5
  47. tests/unit_tests/arelle/test_frozen_dict.py +176 -0
  48. tests/unit_tests/arelle/test_frozen_ordered_set.py +315 -0
  49. tests/unit_tests/arelle/test_import.py +31 -0
  50. tests/unit_tests/arelle/test_ordered_set.py +272 -0
  51. {arelle_release-2.37.17.dist-info → arelle_release-2.37.19.dist-info}/WHEEL +0 -0
  52. {arelle_release-2.37.17.dist-info → arelle_release-2.37.19.dist-info}/entry_points.txt +0 -0
  53. {arelle_release-2.37.17.dist-info → arelle_release-2.37.19.dist-info}/licenses/LICENSE.md +0 -0
  54. {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