arelle-release 2.37.46__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 +15 -8
- arelle/CntlrCmdLine.py +121 -56
- arelle/CntlrWinMain.py +143 -70
- arelle/DialogFind.py +1 -1
- arelle/DialogPluginManager.py +6 -4
- arelle/DisclosureSystem.py +7 -0
- arelle/ErrorManager.py +21 -6
- arelle/FileSource.py +11 -4
- arelle/FunctionIxt.py +16 -11
- arelle/HtmlUtil.py +5 -4
- arelle/LeiUtil.py +63 -43
- arelle/ModelDocument.py +20 -15
- arelle/ModelDtsObject.py +8 -0
- arelle/ModelInstanceObject.py +1 -1
- arelle/ModelObject.py +16 -18
- arelle/ModelObjectFactory.py +35 -17
- arelle/ModelXbrl.py +28 -11
- arelle/PluginManager.py +130 -105
- arelle/RuntimeOptions.py +1 -0
- arelle/UrlUtil.py +14 -0
- arelle/Validate.py +17 -12
- arelle/ValidateDuplicateFacts.py +3 -1
- arelle/ValidateFileSource.py +38 -0
- arelle/ValidateFilingText.py +3 -3
- arelle/ValidateXbrl.py +5 -2
- arelle/ValidateXbrlCalcs.py +210 -186
- arelle/ValidateXbrlDTS.py +1 -1
- arelle/ViewFile.py +1 -0
- arelle/ViewFileFactTable.py +2 -2
- arelle/ViewWinDTS.py +4 -1
- arelle/WebCache.py +28 -24
- arelle/XbrlConst.py +22 -0
- arelle/XmlUtil.py +16 -21
- arelle/XmlValidate.py +6 -9
- arelle/_version.py +16 -3
- arelle/api/Session.py +11 -2
- arelle/config/disclosuresystems.xsd +2 -0
- 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 +26 -13
- arelle/packages/report/ReportPackageConst.py +0 -1
- arelle/plugin/inlineXbrlDocumentSet.py +19 -5
- arelle/plugin/validate/DBA/DisclosureSystems.py +19 -1
- arelle/plugin/validate/DBA/PluginValidationDataExtension.py +2 -4
- arelle/plugin/validate/DBA/ValidationPluginExtension.py +2 -1
- arelle/plugin/validate/DBA/resources/config.xml +5 -0
- arelle/plugin/validate/DBA/rules/__init__.py +2 -2
- 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/Constants.py +193 -9
- arelle/plugin/validate/EDINET/ContextRequirement.py +58 -0
- arelle/plugin/validate/EDINET/ControllerPluginData.py +220 -1
- arelle/plugin/validate/EDINET/CoverItemRequirements.py +42 -0
- arelle/plugin/validate/EDINET/DeiRequirements.py +118 -0
- arelle/plugin/validate/EDINET/FilingFormat.py +275 -0
- arelle/plugin/validate/EDINET/FormType.py +134 -0
- arelle/plugin/validate/EDINET/ManifestInstance.py +72 -5
- arelle/plugin/validate/EDINET/NamespaceConfig.py +50 -0
- arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +493 -132
- arelle/plugin/validate/EDINET/{InstanceType.py → ReportFolderType.py} +72 -15
- arelle/plugin/validate/EDINET/Statement.py +139 -0
- arelle/plugin/validate/EDINET/TableOfContentsBuilder.py +595 -0
- arelle/plugin/validate/EDINET/UploadContents.py +48 -0
- arelle/plugin/validate/EDINET/ValidationPluginExtension.py +20 -2
- arelle/plugin/validate/EDINET/__init__.py +31 -6
- arelle/plugin/validate/EDINET/resources/config.xml +8 -1
- arelle/plugin/validate/EDINET/resources/cover-item-requirements.json +793 -0
- arelle/plugin/validate/EDINET/resources/dei-requirements.csv +27 -0
- arelle/plugin/validate/EDINET/resources/edinet-taxonomies.xml +2 -0
- arelle/plugin/validate/EDINET/rules/contexts.py +375 -14
- arelle/plugin/validate/EDINET/rules/edinet.py +1934 -45
- arelle/plugin/validate/EDINET/rules/frta.py +122 -3
- arelle/plugin/validate/EDINET/rules/gfm.py +1907 -11
- arelle/plugin/validate/EDINET/rules/upload.py +989 -141
- arelle/plugin/validate/ESEF/Const.py +3 -1
- arelle/plugin/validate/ESEF/ESEF_2021/DTS.py +5 -0
- arelle/plugin/validate/ESEF/ESEF_2021/Image.py +2 -2
- arelle/plugin/validate/ESEF/ESEF_2021/ValidateXbrlFinally.py +23 -20
- arelle/plugin/validate/ESEF/ESEF_Current/DTS.py +47 -14
- arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py +100 -25
- arelle/plugin/validate/ESEF/__init__.py +20 -6
- arelle/plugin/validate/ESEF/resources/authority-validations.json +76 -9
- arelle/plugin/validate/ESEF/resources/config.xml +20 -0
- arelle/plugin/validate/NL/DisclosureSystems.py +22 -0
- arelle/plugin/validate/NL/PluginValidationDataExtension.py +27 -9
- arelle/plugin/validate/NL/ValidationPluginExtension.py +51 -7
- arelle/plugin/validate/NL/resources/config.xml +18 -0
- arelle/plugin/validate/NL/rules/br_kvk.py +17 -61
- 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 +31 -147
- arelle/plugin/validate/NL/rules/nl_kvk.py +142 -28
- arelle/plugin/validate/ROS/PluginValidationDataExtension.py +2 -0
- arelle/plugin/validate/ROS/ValidationPluginExtension.py +4 -1
- arelle/plugin/validate/ROS/rules/ros.py +41 -9
- arelle/plugin/validate/UK/ValidateUK.py +130 -66
- arelle/plugin/validate/UK/__init__.py +89 -103
- arelle/utils/EntryPointDetection.py +79 -13
- arelle/utils/PluginHooks.py +125 -0
- arelle/utils/validate/ESEFImage.py +6 -6
- arelle/utils/validate/Validation.py +18 -0
- arelle/utils/validate/ValidationPlugin.py +76 -11
- arelle/utils/validate/ValidationUtil.py +35 -3
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/METADATA +30 -20
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/RECORD +115 -191
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/licenses/LICENSE.md +0 -3
- arelle/archive/CustomLogger.py +0 -43
- arelle/archive/LoadEFMvalidate.py +0 -32
- arelle/archive/LoadSavePreLbCsv.py +0 -26
- arelle/archive/LoadValidate.cs +0 -31
- arelle/archive/LoadValidate.py +0 -36
- arelle/archive/LoadValidateCmdLine.java +0 -69
- arelle/archive/LoadValidatePostedZip.java +0 -57
- arelle/archive/LoadValidateWebService.java +0 -34
- arelle/archive/SaveTableToExelle.py +0 -140
- arelle/archive/TR3toTR4.py +0 -88
- arelle/archive/plugin/ESEF_2022/__init__.py +0 -47
- arelle/archive/plugin/bigInstance.py +0 -394
- arelle/archive/plugin/cmdWebServerExtension.py +0 -43
- arelle/archive/plugin/crashTest.py +0 -38
- arelle/archive/plugin/functionsXmlCreation.py +0 -106
- arelle/archive/plugin/hello_i18n.pot +0 -26
- arelle/archive/plugin/hello_i18n.py +0 -32
- arelle/archive/plugin/importTestChild1.py +0 -21
- arelle/archive/plugin/importTestChild2.py +0 -22
- arelle/archive/plugin/importTestGrandchild1.py +0 -21
- arelle/archive/plugin/importTestGrandchild2.py +0 -21
- arelle/archive/plugin/importTestImported1.py +0 -23
- arelle/archive/plugin/importTestImported11.py +0 -22
- arelle/archive/plugin/importTestParent.py +0 -48
- arelle/archive/plugin/instanceInfo.py +0 -306
- arelle/archive/plugin/loadFromOIM-2018.py +0 -1282
- arelle/archive/plugin/locale/fr/LC_MESSAGES/hello_i18n.po +0 -25
- arelle/archive/plugin/objectmaker.py +0 -285
- arelle/archive/plugin/packagedImportTest/__init__.py +0 -47
- arelle/archive/plugin/packagedImportTest/importTestChild1.py +0 -21
- arelle/archive/plugin/packagedImportTest/importTestChild2.py +0 -22
- arelle/archive/plugin/packagedImportTest/importTestGrandchild1.py +0 -21
- arelle/archive/plugin/packagedImportTest/importTestGrandchild2.py +0 -21
- arelle/archive/plugin/packagedImportTest/importTestImported1.py +0 -24
- arelle/archive/plugin/packagedImportTest/importTestImported11.py +0 -21
- arelle/archive/plugin/packagedImportTest/subdir/importTestImported111.py +0 -21
- arelle/archive/plugin/packagedImportTest/subdir/subsubdir/importTestImported1111.py +0 -21
- arelle/archive/plugin/sakaCalendar.py +0 -215
- arelle/archive/plugin/saveInstanceInfoset.py +0 -121
- arelle/archive/plugin/sphinx/FormulaGenerator.py +0 -823
- arelle/archive/plugin/sphinx/SphinxContext.py +0 -404
- arelle/archive/plugin/sphinx/SphinxEvaluator.py +0 -783
- arelle/archive/plugin/sphinx/SphinxMethods.py +0 -1287
- arelle/archive/plugin/sphinx/SphinxParser.py +0 -1093
- arelle/archive/plugin/sphinx/SphinxValidator.py +0 -163
- arelle/archive/plugin/sphinx/US-GAAP Ratios Example.xsr +0 -52
- arelle/archive/plugin/sphinx/__init__.py +0 -285
- arelle/archive/plugin/streamingExtensions.py +0 -335
- arelle/archive/plugin/updateTableLB.py +0 -242
- arelle/archive/plugin/validate/SBRnl/CustomLoader.py +0 -19
- arelle/archive/plugin/validate/SBRnl/DTS.py +0 -305
- arelle/archive/plugin/validate/SBRnl/Dimensions.py +0 -357
- arelle/archive/plugin/validate/SBRnl/Document.py +0 -799
- arelle/archive/plugin/validate/SBRnl/Filing.py +0 -467
- arelle/archive/plugin/validate/SBRnl/__init__.py +0 -75
- arelle/archive/plugin/validate/SBRnl/config.xml +0 -26
- arelle/archive/plugin/validate/SBRnl/sbr-nl-taxonomies.xml +0 -754
- arelle/archive/plugin/validate/USBestPractices.py +0 -570
- arelle/archive/plugin/validate/USCorpAction.py +0 -557
- arelle/archive/plugin/validate/USSecTagging.py +0 -337
- arelle/archive/plugin/validate/XDC/__init__.py +0 -77
- arelle/archive/plugin/validate/XDC/config.xml +0 -20
- arelle/archive/plugin/validate/XFsyntax/__init__.py +0 -64
- arelle/archive/plugin/validate/XFsyntax/xf.py +0 -2227
- arelle/archive/plugin/validate/calc2.py +0 -536
- arelle/archive/plugin/validateSchemaLxml.py +0 -156
- arelle/archive/plugin/validateTableInfoset.py +0 -52
- arelle/archive/us-gaap-dei-docType-extraction-frm.xml +0 -90
- arelle/archive/us-gaap-dei-ratio-cash-frm.xml +0 -150
- arelle/examples/plugin/formulaSuiteConverter.py +0 -212
- arelle/examples/plugin/functionsCustom.py +0 -59
- arelle/examples/plugin/hello_dolly.py +0 -64
- arelle/examples/plugin/multi.py +0 -58
- arelle/examples/plugin/rssSaveOim.py +0 -96
- arelle/examples/plugin/validate/XYZ/DisclosureSystems.py +0 -2
- arelle/examples/plugin/validate/XYZ/PluginValidationDataExtension.py +0 -10
- arelle/examples/plugin/validate/XYZ/ValidationPluginExtension.py +0 -49
- arelle/examples/plugin/validate/XYZ/__init__.py +0 -75
- arelle/examples/plugin/validate/XYZ/resources/config.xml +0 -16
- arelle/examples/plugin/validate/XYZ/rules/__init__.py +0 -0
- arelle/examples/plugin/validate/XYZ/rules/rules01.py +0 -110
- arelle/examples/plugin/validate/XYZ/rules/rules02.py +0 -59
- 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/scripts-macOS/startWebServer.command +0 -3
- arelle/scripts-unix/startWebServer.sh +0 -1
- arelle/scripts-windows/startWebServer.bat +0 -5
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/WHEEL +0 -0
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.37.46.dist-info → arelle_release-2.38.0.dist-info}/top_level.txt +0 -0
|
@@ -1,783 +0,0 @@
|
|
|
1
|
-
'''
|
|
2
|
-
sphinxEvaluator processes the Sphinx language in the context of an XBRL DTS and instance.
|
|
3
|
-
|
|
4
|
-
See COPYRIGHT.md for copyright information.
|
|
5
|
-
|
|
6
|
-
Sphinx is a Rules Language for XBRL described by a Sphinx 2 Primer
|
|
7
|
-
(c) Copyright 2012 CoreFiling, Oxford UK.
|
|
8
|
-
Sphinx copyright applies to the Sphinx language, not to this software.
|
|
9
|
-
Workiva, Inc. conveys neither rights nor license for the Sphinx language.
|
|
10
|
-
'''
|
|
11
|
-
|
|
12
|
-
import operator
|
|
13
|
-
from .SphinxContext import HyperspaceBindings, HyperspaceBinding
|
|
14
|
-
from .SphinxParser import (astFunctionReference, astHyperspaceExpression, astNode,
|
|
15
|
-
astFormulaRule, astReportRule,
|
|
16
|
-
astVariableReference)
|
|
17
|
-
from .SphinxMethods import (methodImplementation, functionImplementation,
|
|
18
|
-
aggreateFunctionImplementation, aggreateFunctionAcceptsFactArgs,
|
|
19
|
-
moduleInit as SphinxMethodsModuleInit)
|
|
20
|
-
from arelle.ModelFormulaObject import Aspect
|
|
21
|
-
from arelle.ModelValue import QName
|
|
22
|
-
from arelle.ModelInstanceObject import ModelFact
|
|
23
|
-
from arelle.ModelXbrl import DEFAULT, NONDEFAULT, DEFAULTorNONDEFAULT
|
|
24
|
-
from arelle import XbrlConst, XmlUtil
|
|
25
|
-
|
|
26
|
-
class SphinxException(Exception):
|
|
27
|
-
def __init__(self, node, code, message, **kwargs ):
|
|
28
|
-
self.node = node
|
|
29
|
-
self.code = code
|
|
30
|
-
self.message = message
|
|
31
|
-
self.kwargs = kwargs
|
|
32
|
-
self.args = ( self.__repr__(), )
|
|
33
|
-
def __repr__(self):
|
|
34
|
-
return _('[{0}] exception: {1} at {2}').format(self.code, self.message % self.kwargs, self.node.sourceFileLine)
|
|
35
|
-
|
|
36
|
-
class SphinxSpecialValue:
|
|
37
|
-
def __init__(self, name):
|
|
38
|
-
self.name = name
|
|
39
|
-
def __repr__(self):
|
|
40
|
-
return self.name
|
|
41
|
-
|
|
42
|
-
UNBOUND = SphinxSpecialValue("unbound")
|
|
43
|
-
NONE = SphinxSpecialValue("none")
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def evaluateRuleBase(sphinxContext):
|
|
47
|
-
|
|
48
|
-
# clear any residual values
|
|
49
|
-
for constantNode in sphinxContext.constants.values():
|
|
50
|
-
constantNode.value = None
|
|
51
|
-
|
|
52
|
-
clearEvaluation(sphinxContext)
|
|
53
|
-
|
|
54
|
-
# check any rule-base preconditions
|
|
55
|
-
for preconditionNode in sphinxContext.ruleBasePreconditionNodes:
|
|
56
|
-
preconditionPasses = evaluate(preconditionNode, sphinxContext)
|
|
57
|
-
clearEvaluation(sphinxContext)
|
|
58
|
-
if not preconditionPasses:
|
|
59
|
-
return
|
|
60
|
-
|
|
61
|
-
# evaluate rules
|
|
62
|
-
for ruleProg in sphinxContext.rules:
|
|
63
|
-
evaluate(ruleProg, sphinxContext)
|
|
64
|
-
clearEvaluation(sphinxContext)
|
|
65
|
-
|
|
66
|
-
# dereference constants
|
|
67
|
-
for constantNode in sphinxContext.constants.values():
|
|
68
|
-
constantNode.value = None
|
|
69
|
-
|
|
70
|
-
def clearEvaluation(sphinxContext):
|
|
71
|
-
sphinxContext.tags.clear()
|
|
72
|
-
sphinxContext.localVariables.clear()
|
|
73
|
-
while sphinxContext.hyperspaceBindings:
|
|
74
|
-
sphinxContext.hyperspaceBindings.close() # resets sphinxContext.hyperspaceBindings to parent bindings
|
|
75
|
-
|
|
76
|
-
def evaluate(node, sphinxContext, value=False, fallback=None, hsBoundFact=False):
|
|
77
|
-
if isinstance(node, astNode):
|
|
78
|
-
if fallback is None:
|
|
79
|
-
result = evaluator[node.__class__.__name__](node, sphinxContext)
|
|
80
|
-
else:
|
|
81
|
-
try:
|
|
82
|
-
result = evaluator[node.__class__.__name__](node, sphinxContext)
|
|
83
|
-
except StopIteration:
|
|
84
|
-
if sphinxContext.formulaOptions.traceVariableSetExpressionEvaluation:
|
|
85
|
-
sphinxContext.modelXbrl.info("sphinx:trace",
|
|
86
|
-
_("%(node)s has unbound evaluation"),
|
|
87
|
-
sourceFileLine=node.sourceFileLine, node=str(node))
|
|
88
|
-
return fallback
|
|
89
|
-
if sphinxContext.formulaOptions.traceVariableSetExpressionEvaluation:
|
|
90
|
-
sphinxContext.modelXbrl.info("sphinx:trace",
|
|
91
|
-
_("%(node)s evaluation: %(value)s"),
|
|
92
|
-
sourceFileLine=node.sourceFileLine, node=str(node), value=result)
|
|
93
|
-
if result is not None:
|
|
94
|
-
if isinstance(result, HyperspaceBinding):
|
|
95
|
-
if hsBoundFact: # return fact, not the value of fact
|
|
96
|
-
return result.yieldedFact
|
|
97
|
-
elif value:
|
|
98
|
-
return result.value
|
|
99
|
-
# dereference nodes to their value
|
|
100
|
-
if (value or hsBoundFact) and isinstance(result, astNode):
|
|
101
|
-
return evaluate(result, sphinxContext, value, fallback, hsBoundFact)
|
|
102
|
-
return result
|
|
103
|
-
return result
|
|
104
|
-
elif isinstance(node, (tuple,list)):
|
|
105
|
-
return [evaluate(item, sphinxContext, value, fallback, hsBoundFact)
|
|
106
|
-
for item in node]
|
|
107
|
-
elif isinstance(node, set):
|
|
108
|
-
return set(evaluate(item, sphinxContext, value, fallback, hsBoundFact)
|
|
109
|
-
for item in node)
|
|
110
|
-
else:
|
|
111
|
-
return node
|
|
112
|
-
|
|
113
|
-
def evaluateAnnotationDeclaration(node, sphinxContext):
|
|
114
|
-
return None
|
|
115
|
-
|
|
116
|
-
def evaluateBinaryOperation(node, sphinxContext):
|
|
117
|
-
leftValue = evaluate(node.leftExpr, sphinxContext, value=True, fallback=UNBOUND)
|
|
118
|
-
rightValue = evaluate(node.rightExpr, sphinxContext, value=True, fallback=UNBOUND)
|
|
119
|
-
op = node.op
|
|
120
|
-
if sphinxContext.formulaOptions.traceVariableExpressionEvaluation:
|
|
121
|
-
sphinxContext.modelXbrl.info("sphinx:trace",
|
|
122
|
-
_("Binary op %(op)s v1: %(leftValue)s, v2: %(rightValue)s"),
|
|
123
|
-
sourceFileLine=node.sourceFileLine, op=op, leftValue=leftValue, rightValue=rightValue)
|
|
124
|
-
if op == ":=":
|
|
125
|
-
if sphinxContext.ruleNode.bind == "left":
|
|
126
|
-
if rightValue is UNBOUND: raise StopIteration
|
|
127
|
-
elif sphinxContext.ruleNode.bind == "right":
|
|
128
|
-
if leftValue is UNBOUND: raise StopIteration
|
|
129
|
-
elif sphinxContext.ruleNode.bind == "either":
|
|
130
|
-
if leftValue is UNBOUND and rightValue is UNBOUND: raise StopIteration
|
|
131
|
-
else: # both or default
|
|
132
|
-
if leftValue is UNBOUND or rightValue is UNBOUND: raise StopIteration
|
|
133
|
-
return (leftValue, rightValue)
|
|
134
|
-
elif op in {"|+|", "|+", "+|", "+", "|-|", "|-", "-|", "-"}:
|
|
135
|
-
if leftValue is UNBOUND:
|
|
136
|
-
if op[0] == '|':
|
|
137
|
-
raise StopIteration
|
|
138
|
-
else:
|
|
139
|
-
leftValue = 0
|
|
140
|
-
if rightValue is UNBOUND:
|
|
141
|
-
if op[-1] == '|':
|
|
142
|
-
raise StopIteration
|
|
143
|
-
else:
|
|
144
|
-
rightValue = 0
|
|
145
|
-
else:
|
|
146
|
-
if leftValue is UNBOUND:
|
|
147
|
-
return UNBOUND
|
|
148
|
-
if rightValue is UNBOUND:
|
|
149
|
-
if op == "or" and leftValue:
|
|
150
|
-
return True
|
|
151
|
-
return UNBOUND
|
|
152
|
-
if op == "/" and rightValue == 0: # prevent divide by zero
|
|
153
|
-
return UNBOUND
|
|
154
|
-
try:
|
|
155
|
-
result = {'+': operator.add, '-': operator.sub, '*': operator.mul, '/': operator.truediv,
|
|
156
|
-
'<': operator.lt, '>': operator.gt, '<=': operator.le, '>=': operator.ge,
|
|
157
|
-
'==': operator.eq, '!=': operator.ne,
|
|
158
|
-
'and': operator.and_, 'or': operator.or_,
|
|
159
|
-
}[op](leftValue, rightValue)
|
|
160
|
-
return result
|
|
161
|
-
except KeyError:
|
|
162
|
-
sphinxContext.modelXbrl.error("sphinx:error",
|
|
163
|
-
_("Operation \"%(op)s\" not implemented for %(node)s"),
|
|
164
|
-
sourceFileLine=node.sourceFileLine, op=op, node=str(node))
|
|
165
|
-
except (TypeError, ZeroDivisionError) as err:
|
|
166
|
-
sphinxContext.modelXbrl.error("sphinx:error",
|
|
167
|
-
_("Operation \"%(op)s\" raises exception %(error)s for %(node)s"),
|
|
168
|
-
sourceFileLine=node.sourceFileLine, op=op, node=str(node), error=str(err))
|
|
169
|
-
return None
|
|
170
|
-
|
|
171
|
-
def evaluateConstant(node, sphinxContext):
|
|
172
|
-
if node.value is None: # first time
|
|
173
|
-
hsBindings = HyperspaceBindings(sphinxContext) # must have own hsBindings from caller
|
|
174
|
-
previousLocalVariables = sphinxContext.localVariables # save local variables
|
|
175
|
-
sphinxContext.localVariables = {}
|
|
176
|
-
node.value = evaluate(node.expr, sphinxContext)
|
|
177
|
-
if sphinxContext.formulaOptions.traceVariableSetExpressionEvaluation:
|
|
178
|
-
sphinxContext.modelXbrl.info("sphinx:trace",
|
|
179
|
-
_("Constant %(name)s assigned value: %(value)s"),
|
|
180
|
-
sourceFileLine=node.sourceFileLine, name=node.constantName, value=node.value)
|
|
181
|
-
hsBindings.close()
|
|
182
|
-
sphinxContext.localVariables = previousLocalVariables
|
|
183
|
-
return node.value
|
|
184
|
-
|
|
185
|
-
def evaluateFor(node, sphinxContext):
|
|
186
|
-
# add a hyperspaceBinding to sphinxContext for this node
|
|
187
|
-
hsBindings = sphinxContext.hyperspaceBindings
|
|
188
|
-
forBinding = hsBindings.forBinding(node)
|
|
189
|
-
# set variable here because although needed for next() operation, will be cleared outside of for's context
|
|
190
|
-
sphinxContext.localVariables[node.name] = forBinding.yieldedValue
|
|
191
|
-
return evaluate(node.expr, sphinxContext)
|
|
192
|
-
|
|
193
|
-
def evaluateFunctionDeclaration(node, sphinxContext, args):
|
|
194
|
-
overriddenVariables = {}
|
|
195
|
-
|
|
196
|
-
if isinstance(args, dict):
|
|
197
|
-
# args may not all be used in the function declaration, just want used ones
|
|
198
|
-
argDict = dict((name, value)
|
|
199
|
-
for name, value in args.items()
|
|
200
|
-
if name in node.params)
|
|
201
|
-
else: # purely positional args
|
|
202
|
-
# positional parameters named according to function prototype
|
|
203
|
-
if len(args) != len(node.params):
|
|
204
|
-
sphinxContext.modelXbrl.log("ERROR", "sphinx.functionArgumentsMismatch",
|
|
205
|
-
_("Function %(name)s requires %(required)s parameters but %(provided)s are provided"),
|
|
206
|
-
sourceFileLine=node.sourceFileLine,
|
|
207
|
-
name=node.name, required=len(node.params), provided=len(args))
|
|
208
|
-
return None
|
|
209
|
-
argDict = dict((paramName, args[i])
|
|
210
|
-
for i, paramName in enumerate(node.params))
|
|
211
|
-
for name, value in argDict.items():
|
|
212
|
-
if name in sphinxContext.localVariables:
|
|
213
|
-
overriddenVariables[name] = sphinxContext.localVariables[name]
|
|
214
|
-
sphinxContext.localVariables[name] = value
|
|
215
|
-
|
|
216
|
-
def clearFunctionArgs():
|
|
217
|
-
for name in argDict.keys():
|
|
218
|
-
del sphinxContext.localVariables[name]
|
|
219
|
-
sphinxContext.localVariables.update(overriddenVariables)
|
|
220
|
-
overriddenVariables.clear()
|
|
221
|
-
|
|
222
|
-
try:
|
|
223
|
-
result = evaluate(node.expr, sphinxContext)
|
|
224
|
-
clearFunctionArgs()
|
|
225
|
-
return result
|
|
226
|
-
except StopIteration as ex:
|
|
227
|
-
clearFunctionArgs()
|
|
228
|
-
raise ex # reraise exception
|
|
229
|
-
|
|
230
|
-
def evaluateFunctionReference(node, sphinxContext):
|
|
231
|
-
name = node.name
|
|
232
|
-
if name in ("error", "warning", "info", "pass"):
|
|
233
|
-
sphinxContext.dynamicSeverity = node.name
|
|
234
|
-
elif name == "unbound":
|
|
235
|
-
return UNBOUND
|
|
236
|
-
|
|
237
|
-
if name in aggreateFunctionImplementation:
|
|
238
|
-
return evaluateAggregateFunction(node, sphinxContext, name)
|
|
239
|
-
|
|
240
|
-
if name in sphinxContext.functions: # user defined function
|
|
241
|
-
resolveValues = sphinxContext.functions[name].functionType == "function"
|
|
242
|
-
namedParametersAssignedTo = sphinxContext.localVariables
|
|
243
|
-
else:
|
|
244
|
-
resolveValues = True
|
|
245
|
-
if name in ("error", "warning", "info", "pass"):
|
|
246
|
-
namedParametersAssignedTo = sphinxContext.tags
|
|
247
|
-
else:
|
|
248
|
-
namedParametersAssignedTo = sphinxContext.localVariables
|
|
249
|
-
|
|
250
|
-
# evaluate local variables
|
|
251
|
-
for localVar in node.localVariables:
|
|
252
|
-
evaluate(localVar, sphinxContext)
|
|
253
|
-
# evaluate args
|
|
254
|
-
args = []
|
|
255
|
-
tagName = None
|
|
256
|
-
l = len(node.args)
|
|
257
|
-
for i in range(l):
|
|
258
|
-
arg = node.args[i]
|
|
259
|
-
if arg == "=":
|
|
260
|
-
if i > 0:
|
|
261
|
-
tagName = node.args[i-1]
|
|
262
|
-
elif i == l - 1 or node.args[i+1] != "=":
|
|
263
|
-
if resolveValues: # macros pass in the argument, not value
|
|
264
|
-
arg = evaluate(arg, sphinxContext, value=True)
|
|
265
|
-
elif (isinstance(arg, astVariableReference) and
|
|
266
|
-
getattr(sphinxContext.localVariables.get(arg.variableName),
|
|
267
|
-
"isMacroParameter", False)):
|
|
268
|
-
# pass original macro parameter, not a reference to it (otherwise causes looping)
|
|
269
|
-
arg = sphinxContext.localVariables[arg.variableName]
|
|
270
|
-
elif isinstance(arg, astNode):
|
|
271
|
-
arg.isMacroParameter = True
|
|
272
|
-
args.append(arg)
|
|
273
|
-
if tagName:
|
|
274
|
-
namedParametersAssignedTo[tagName] = arg
|
|
275
|
-
tagName = None
|
|
276
|
-
|
|
277
|
-
if name in ("error", "warning", "info", "pass"):
|
|
278
|
-
result = None
|
|
279
|
-
|
|
280
|
-
# call function here
|
|
281
|
-
elif name in sphinxContext.functions: # user defined function
|
|
282
|
-
result = evaluateFunctionDeclaration(sphinxContext.functions[name], sphinxContext, args)
|
|
283
|
-
|
|
284
|
-
# call built-in functions
|
|
285
|
-
elif name in functionImplementation:
|
|
286
|
-
result = functionImplementation[name](node, sphinxContext, args)
|
|
287
|
-
|
|
288
|
-
else:
|
|
289
|
-
raise SphinxException(node,
|
|
290
|
-
"sphinx:functionName",
|
|
291
|
-
_("unassigned function name %(name)s"),
|
|
292
|
-
name=name)
|
|
293
|
-
|
|
294
|
-
# remove local variables
|
|
295
|
-
for localVar in node.localVariables:
|
|
296
|
-
del sphinxContext.localVariables[localVar.name]
|
|
297
|
-
return result
|
|
298
|
-
|
|
299
|
-
def evaluateAggregateFunction(node, sphinxContext, name):
|
|
300
|
-
# determine if evaluating args found hyperspace (first time)
|
|
301
|
-
args = []
|
|
302
|
-
iterateAbove, bindingsLen = getattr(node, "aggregationHsBindings", (None, None))
|
|
303
|
-
firstTime = bindingsLen is None
|
|
304
|
-
hsBindings = sphinxContext.hyperspaceBindings
|
|
305
|
-
parentAggregationNode = hsBindings.aggregationNode
|
|
306
|
-
parentIsValuesIteration = hsBindings.isValuesIteration
|
|
307
|
-
hsBindings.aggregationNode = node # block removing nested aspect bindings
|
|
308
|
-
hsBindings.isValuesIteration = False
|
|
309
|
-
prevHsBindingsLen = len(hsBindings.hyperspaceBindings)
|
|
310
|
-
hsBoundFact = aggreateFunctionAcceptsFactArgs[name]
|
|
311
|
-
arg = node.args[0]
|
|
312
|
-
try:
|
|
313
|
-
while (True): # possibly multiple bindings
|
|
314
|
-
# evaluate local variables
|
|
315
|
-
for localVar in node.localVariables:
|
|
316
|
-
evaluate(localVar, sphinxContext)
|
|
317
|
-
|
|
318
|
-
value = evaluate(arg, sphinxContext, value=True, hsBoundFact=hsBoundFact)
|
|
319
|
-
if isinstance(value, (list,set)):
|
|
320
|
-
for listArg in value:
|
|
321
|
-
if value is not UNBOUND:
|
|
322
|
-
args.append(evaluate(listArg, sphinxContext, value=True))
|
|
323
|
-
elif value is not UNBOUND:
|
|
324
|
-
args.append(value)
|
|
325
|
-
if firstTime:
|
|
326
|
-
if len(hsBindings.hyperspaceBindings) == prevHsBindingsLen:
|
|
327
|
-
# no hs bindings, just scalar
|
|
328
|
-
break
|
|
329
|
-
else: # has hs bindings, evaluate rest of them
|
|
330
|
-
firstTime = False
|
|
331
|
-
iterateAbove = prevHsBindingsLen - 1
|
|
332
|
-
bindingsLen = len(hsBindings.hyperspaceBindings)
|
|
333
|
-
node.aggregationHsBindings = (iterateAbove, bindingsLen)
|
|
334
|
-
hsBindings.next(iterateAbove, bindingsLen)
|
|
335
|
-
except StopIteration:
|
|
336
|
-
pass # no more bindings
|
|
337
|
-
hsBindings.isValuesIteration = parentIsValuesIteration
|
|
338
|
-
hsBindings.aggregationNode = parentAggregationNode
|
|
339
|
-
# remove local variables
|
|
340
|
-
for localVar in node.localVariables:
|
|
341
|
-
if localVar in sphinxContext.localVariables:
|
|
342
|
-
del sphinxContext.localVariables[localVar.name]
|
|
343
|
-
if sphinxContext.formulaOptions.traceVariableExpressionEvaluation:
|
|
344
|
-
sphinxContext.modelXbrl.info("sphinx:trace",
|
|
345
|
-
_("Aggregative function %(name)s arguments: %(args)s"),
|
|
346
|
-
sourceFileLine=node.sourceFileLine, name=name,
|
|
347
|
-
args=",".join(str(a) for a in args))
|
|
348
|
-
try:
|
|
349
|
-
return aggreateFunctionImplementation[name](node, sphinxContext, args)
|
|
350
|
-
except (TypeError, ZeroDivisionError) as err:
|
|
351
|
-
sphinxContext.modelXbrl.error("sphinx:error",
|
|
352
|
-
_("Function %(name)s raises exception %(error)s in %(node)s"),
|
|
353
|
-
sourceFileLine=node.sourceFileLine, name=name, node=str(node), error=str(err))
|
|
354
|
-
return None
|
|
355
|
-
|
|
356
|
-
def evaluateHyperspaceExpression(node, sphinxContext):
|
|
357
|
-
# add a hyperspaceBinding to sphinxContext for this node
|
|
358
|
-
hsBindings = sphinxContext.hyperspaceBindings
|
|
359
|
-
nodeBinding = hsBindings.nodeBinding(node)
|
|
360
|
-
return nodeBinding
|
|
361
|
-
|
|
362
|
-
def evaluateIf(node, sphinxContext):
|
|
363
|
-
condition = evaluate(node.condition, sphinxContext, value=True)
|
|
364
|
-
if condition:
|
|
365
|
-
expr = node.thenExpr
|
|
366
|
-
else:
|
|
367
|
-
expr = node.elseExpr
|
|
368
|
-
return evaluate(expr, sphinxContext)
|
|
369
|
-
|
|
370
|
-
def evaluateMessage(node, sphinxContext, resultTags, hsBindings):
|
|
371
|
-
def evaluateTagExpr(tagExpr, modifier):
|
|
372
|
-
if modifier == "value":
|
|
373
|
-
value = evaluate(tagExpr, sphinxContext, value=True)
|
|
374
|
-
elif modifier == "context":
|
|
375
|
-
value = contextView(sphinxContext, tagExpr)
|
|
376
|
-
else:
|
|
377
|
-
value = "{0} {1}".format(evaluate(tagExpr, sphinxContext, value=True),
|
|
378
|
-
contextView(sphinxContext))
|
|
379
|
-
return value
|
|
380
|
-
|
|
381
|
-
msgstr = evaluate(node.message, sphinxContext, value=True)
|
|
382
|
-
text = []
|
|
383
|
-
args = []
|
|
384
|
-
i = 0
|
|
385
|
-
while True:
|
|
386
|
-
j = msgstr.find("${", i)
|
|
387
|
-
if j >= 0:
|
|
388
|
-
text.append(msgstr[i:j]) # previous part of string
|
|
389
|
-
k = msgstr.find("}", j+2)
|
|
390
|
-
if k > j:
|
|
391
|
-
text.append("{" + str(len(args)) + "}")
|
|
392
|
-
tag, sep, modifier = msgstr[j+2:k].strip().partition(".")
|
|
393
|
-
if tag == "context":
|
|
394
|
-
value = contextView(sphinxContext),
|
|
395
|
-
elif tag in resultTags:
|
|
396
|
-
value = evaluateTagExpr(resultTags.tags[tag], modifier)
|
|
397
|
-
elif tag in sphinxContext.tags:
|
|
398
|
-
value = evaluateTagExpr(sphinxContext.tags[tag], modifier)
|
|
399
|
-
elif tag in sphinxContext.taggedConstants:
|
|
400
|
-
value = evaluateTagExpr(evaluateConstant(sphinxContext.taggedConstants[tag], sphinxContext), modifier)
|
|
401
|
-
elif tag in ("trace", "left", "right", "difference"):
|
|
402
|
-
value = 'Tag "{0}" is not yet supported'.format(tag)
|
|
403
|
-
else:
|
|
404
|
-
sphinxContext.modelXbrl.log("ERROR", "sphinx.unboundMessageTag",
|
|
405
|
-
_("Validation rule tag %(tag)s is not Bound"),
|
|
406
|
-
sourceFileLine=node.sourceFileLine,
|
|
407
|
-
tag=tag)
|
|
408
|
-
value = "${" + tag + "}"
|
|
409
|
-
args.append(value)
|
|
410
|
-
|
|
411
|
-
i = k + 1
|
|
412
|
-
else:
|
|
413
|
-
text.append(msgstr[i:])
|
|
414
|
-
break
|
|
415
|
-
messageStr = ''.join(text)
|
|
416
|
-
return messageStr.format(*args)
|
|
417
|
-
|
|
418
|
-
def evaluateMethodReference(node, sphinxContext):
|
|
419
|
-
args = []
|
|
420
|
-
for i, nodeArg in enumerate(node.args):
|
|
421
|
-
arg = evaluate(nodeArg,
|
|
422
|
-
sphinxContext,
|
|
423
|
-
value=True,
|
|
424
|
-
hsBoundFact=(i == 0)) # don't deref arg 0
|
|
425
|
-
args.append(arg)
|
|
426
|
-
return methodImplementation.get(node.name, # requested method
|
|
427
|
-
methodImplementation["unknown"] # default if missing method
|
|
428
|
-
)(node, sphinxContext, args)
|
|
429
|
-
|
|
430
|
-
def evaluateNoOp(node, sphinxContext):
|
|
431
|
-
return None
|
|
432
|
-
|
|
433
|
-
def evaluateNumericLiteral(node, sphinxContext):
|
|
434
|
-
return node.value
|
|
435
|
-
|
|
436
|
-
def evaluatePreconditionDeclaration(node, sphinxContext):
|
|
437
|
-
hsBindings = HyperspaceBindings(sphinxContext)
|
|
438
|
-
result = evaluate(node.expr, sphinxContext, value=True)
|
|
439
|
-
hsBindings.close()
|
|
440
|
-
return result
|
|
441
|
-
|
|
442
|
-
def evaluatePreconditionReference(node, sphinxContext):
|
|
443
|
-
preconditionPasses = True
|
|
444
|
-
for name in node.names:
|
|
445
|
-
if name in sphinxContext.preconditionNodes:
|
|
446
|
-
if not evaluate(sphinxContext.preconditionNodes[name], sphinxContext, value=True):
|
|
447
|
-
preconditionPasses = False
|
|
448
|
-
clearEvaluation(sphinxContext)
|
|
449
|
-
if not preconditionPasses:
|
|
450
|
-
break
|
|
451
|
-
return preconditionPasses
|
|
452
|
-
|
|
453
|
-
def evaluateQnameLiteral(node, sphinxContext):
|
|
454
|
-
return node.value
|
|
455
|
-
|
|
456
|
-
def evaluateReportRule(node, sphinxContext):
|
|
457
|
-
return None
|
|
458
|
-
|
|
459
|
-
def evaluateRuleBasePrecondition(node, sphinxContext):
|
|
460
|
-
if node.precondition:
|
|
461
|
-
return evaluate(node.precondition, sphinxContext, value=True)
|
|
462
|
-
return True
|
|
463
|
-
|
|
464
|
-
def evaluateStringLiteral(node, sphinxContext):
|
|
465
|
-
return node.text
|
|
466
|
-
|
|
467
|
-
def evaluateTagAssignment(node, sphinxContext):
|
|
468
|
-
result = evaluate(node.expr, sphinxContext, value=True)
|
|
469
|
-
sphinxContext.tags[node.tagName] = result
|
|
470
|
-
return result
|
|
471
|
-
|
|
472
|
-
def evaluateTagReference(node, sphinxContext):
|
|
473
|
-
try:
|
|
474
|
-
return sphinxContext.tags[node.name]
|
|
475
|
-
except KeyError:
|
|
476
|
-
raise SphinxException(node,
|
|
477
|
-
"sphinx:tagName",
|
|
478
|
-
_("unassigned tag name %(name)s"),
|
|
479
|
-
name=node.name )
|
|
480
|
-
|
|
481
|
-
def evaluateRule(node, sphinxContext):
|
|
482
|
-
isFormulaRule = isinstance(node, astFormulaRule)
|
|
483
|
-
isReportRule = isinstance(node, astReportRule)
|
|
484
|
-
name = (node.name or ("sphinx.report" if isReportRule else "sphinx.raise"))
|
|
485
|
-
nodeId = node.nodeTypeName + ' ' + name
|
|
486
|
-
if node.precondition:
|
|
487
|
-
result = evaluate(node.precondition, sphinxContext, value=True)
|
|
488
|
-
if sphinxContext.formulaOptions.traceVariableSetExpressionResult:
|
|
489
|
-
sphinxContext.modelXbrl.info("sphinx:trace",
|
|
490
|
-
_("%(node)s precondition evaluation: %(value)s"),
|
|
491
|
-
sourceFileLine=node.sourceFileLine, node=nodeId, value=result)
|
|
492
|
-
if not result:
|
|
493
|
-
return None
|
|
494
|
-
# nest hyperspace binding
|
|
495
|
-
sphinxContext.ruleNode = node
|
|
496
|
-
hsBindings = None
|
|
497
|
-
ruleIteration = 0
|
|
498
|
-
try:
|
|
499
|
-
hsBindings = HyperspaceBindings(sphinxContext)
|
|
500
|
-
while True:
|
|
501
|
-
ruleIteration += 1
|
|
502
|
-
sphinxContext.dynamicSeverity = None
|
|
503
|
-
sphinxContext.tags.clear()
|
|
504
|
-
sphinxContext.localVariables.clear()
|
|
505
|
-
if sphinxContext.formulaOptions.traceVariableSetExpressionResult:
|
|
506
|
-
sphinxContext.modelXbrl.info("sphinx:trace",
|
|
507
|
-
_("%(node)s starting iteration %(iteration)s"),
|
|
508
|
-
sourceFileLine=node.sourceFileLine, node=nodeId, iteration=ruleIteration)
|
|
509
|
-
for varAssignNode in node.variableAssignments:
|
|
510
|
-
evaluateVariableAssignment(varAssignNode, sphinxContext)
|
|
511
|
-
result = evaluate(node.expr, sphinxContext, value=True)
|
|
512
|
-
if result is UNBOUND:
|
|
513
|
-
result = None # nothing to do for this pass
|
|
514
|
-
elif isFormulaRule:
|
|
515
|
-
left, right = result
|
|
516
|
-
if left is UNBOUND:
|
|
517
|
-
difference = UNBOUND
|
|
518
|
-
elif right is UNBOUND:
|
|
519
|
-
difference = UNBOUND
|
|
520
|
-
else:
|
|
521
|
-
difference = abs(left - right)
|
|
522
|
-
result = difference != 0
|
|
523
|
-
resultTags = {"left": left, "right": right, "difference": difference}
|
|
524
|
-
sphinxContext.dynamicSeverity = None
|
|
525
|
-
if node.severity in sphinxContext.functions:
|
|
526
|
-
evaluateFunctionDeclaration(sphinxContext.functions[node.severity],
|
|
527
|
-
sphinxContext,
|
|
528
|
-
{"difference": difference, "left": left, "right": right})
|
|
529
|
-
if sphinxContext.dynamicSeverity is None or sphinxContext.dynamicSeverity == "pass": # don't process pass
|
|
530
|
-
sphinxContext.dynamicSeverity = None
|
|
531
|
-
result = False
|
|
532
|
-
else:
|
|
533
|
-
if isReportRule:
|
|
534
|
-
resultTags = {"value": result}
|
|
535
|
-
else:
|
|
536
|
-
resultTags = {}
|
|
537
|
-
if sphinxContext.formulaOptions.traceVariableSetExpressionResult:
|
|
538
|
-
sphinxContext.modelXbrl.info("sphinx:trace",
|
|
539
|
-
_("%(node)s result %(result)s %(severity)s iteration %(iteration)s"),
|
|
540
|
-
sourceFileLine=node.sourceFileLine, node=nodeId, iteration=ruleIteration,
|
|
541
|
-
result=result,
|
|
542
|
-
severity=(sphinxContext.dynamicSeverity or node.severity or
|
|
543
|
-
("info" if isReportRule else "error")))
|
|
544
|
-
if ((result or isReportRule) or
|
|
545
|
-
(sphinxContext.dynamicSeverity and sphinxContext.dynamicSeverity != "pass")):
|
|
546
|
-
severity = (sphinxContext.dynamicSeverity or node.severity or
|
|
547
|
-
("info" if isReportRule else "error"))
|
|
548
|
-
if isinstance(severity, astFunctionReference):
|
|
549
|
-
severity = severity.name
|
|
550
|
-
logSeverity = {"error" : "ERROR", "warning": "WARNING", "info": "INFO"}[severity]
|
|
551
|
-
if node.message:
|
|
552
|
-
sphinxContext.modelXbrl.log(logSeverity, name,
|
|
553
|
-
evaluateMessage(node.message, sphinxContext, resultTags, hsBindings),
|
|
554
|
-
sourceFileLine=[node.sourceFileLine] +
|
|
555
|
-
[(fact.modelDocument.uri, fact.sourceline) for fact in hsBindings.boundFacts],
|
|
556
|
-
severity=severity)
|
|
557
|
-
elif isFormulaRule:
|
|
558
|
-
sphinxContext.modelXbrl.log(logSeverity,
|
|
559
|
-
name,
|
|
560
|
-
_("Formula %(severity)s difference %(value)s for %(aspects)s"),
|
|
561
|
-
sourceFileLine=[node.sourceFileLine] +
|
|
562
|
-
[(fact.modelDocument.uri, fact.sourceline) for fact in hsBindings.boundFacts],
|
|
563
|
-
severity=severity,
|
|
564
|
-
value=difference,
|
|
565
|
-
aspects=contextView(sphinxContext))
|
|
566
|
-
elif isReportRule:
|
|
567
|
-
sphinxContext.modelXbrl.log(logSeverity,
|
|
568
|
-
name,
|
|
569
|
-
_("Report %(severity)s %(value)s for %(aspects)s"),
|
|
570
|
-
sourceFileLine=[node.sourceFileLine] +
|
|
571
|
-
[(fact.modelDocument.uri, fact.sourceline) for fact in hsBindings.boundFacts],
|
|
572
|
-
severity=severity,
|
|
573
|
-
value=result,
|
|
574
|
-
aspects=contextView(sphinxContext))
|
|
575
|
-
else:
|
|
576
|
-
sphinxContext.modelXbrl.log(logSeverity,
|
|
577
|
-
name,
|
|
578
|
-
_("Validation rule %(severity)s for %(aspects)s"),
|
|
579
|
-
sourceFileLine=[node.sourceFileLine] +
|
|
580
|
-
[(fact.modelDocument.uri, fact.sourceline) for fact in hsBindings.boundFacts],
|
|
581
|
-
severity=severity,
|
|
582
|
-
aspects=contextView(sphinxContext))
|
|
583
|
-
hsBindings.next() # raises StopIteration when done
|
|
584
|
-
except StopIteration:
|
|
585
|
-
if sphinxContext.formulaOptions.traceVariableSetExpressionResult:
|
|
586
|
-
sphinxContext.modelXbrl.info("sphinx:trace",
|
|
587
|
-
_("%(node)s StopIteration"),
|
|
588
|
-
sourceFileLine=node.sourceFileLine, node=nodeId)
|
|
589
|
-
except SphinxException as ex:
|
|
590
|
-
sphinxContext.modelXbrl.log("ERROR",
|
|
591
|
-
ex.code,
|
|
592
|
-
_("Exception in %(node)s: %(exception)s"),
|
|
593
|
-
node=nodeId,
|
|
594
|
-
ruleName=name,
|
|
595
|
-
exception=ex.message % ex.kwargs,
|
|
596
|
-
sourceFileLine=[node.sourceFileLine] + ([ex.node.sourceFileLine] if ex.node is not node else []),
|
|
597
|
-
**ex.kwargs)
|
|
598
|
-
if hsBindings is not None:
|
|
599
|
-
hsBindings.close()
|
|
600
|
-
return None
|
|
601
|
-
|
|
602
|
-
def noop(arg):
|
|
603
|
-
return arg
|
|
604
|
-
|
|
605
|
-
def evaluateUnaryOperation(node, sphinxContext):
|
|
606
|
-
if node.op == "brackets": # parentheses around an expression
|
|
607
|
-
return node.expr
|
|
608
|
-
value = evaluate(node.expr, sphinxContext, value=True, fallback=UNBOUND)
|
|
609
|
-
if value is UNBOUND:
|
|
610
|
-
return UNBOUND
|
|
611
|
-
try:
|
|
612
|
-
result = {'+': operator.pos, '-': operator.neg, 'not': operator.not_,
|
|
613
|
-
'values': noop,
|
|
614
|
-
}[node.op](value)
|
|
615
|
-
return result
|
|
616
|
-
except KeyError:
|
|
617
|
-
sphinxContext.modelXbrl.error("sphinx:error",
|
|
618
|
-
_("%(node)s operation %(op)s not implemented"),
|
|
619
|
-
modelObject=node, op=node.op)
|
|
620
|
-
return None
|
|
621
|
-
|
|
622
|
-
def evaluateValuesIteration(node, sphinxContext):
|
|
623
|
-
hsBindings = sphinxContext.hyperspaceBindings
|
|
624
|
-
if hsBindings.aggregationNode is None:
|
|
625
|
-
sphinxContext.modelXbrl.error("sphinx:warning",
|
|
626
|
-
_("Values iteration expected to be nested in an aggregating function"),
|
|
627
|
-
modelObject=node)
|
|
628
|
-
else:
|
|
629
|
-
hsBindings.isValuesIteration = True
|
|
630
|
-
return evaluate(node.expr, sphinxContext)
|
|
631
|
-
|
|
632
|
-
def evaluateVariableAssignment(node, sphinxContext):
|
|
633
|
-
result = evaluate(node.expr, sphinxContext)
|
|
634
|
-
sphinxContext.localVariables[node.variableName] = result
|
|
635
|
-
if node.tagName:
|
|
636
|
-
sphinxContext.tags[node.tagName] = result
|
|
637
|
-
return result
|
|
638
|
-
|
|
639
|
-
def evaluateVariableReference(node, sphinxContext):
|
|
640
|
-
try:
|
|
641
|
-
return sphinxContext.localVariables[node.variableName]
|
|
642
|
-
except KeyError:
|
|
643
|
-
if node.variableName in sphinxContext.constants:
|
|
644
|
-
return evaluateConstant(sphinxContext.constants[node.variableName], sphinxContext)
|
|
645
|
-
raise SphinxException(node,
|
|
646
|
-
"sphinx:variableName",
|
|
647
|
-
_("unassigned variable name %(name)s"),
|
|
648
|
-
name=node.variableName)
|
|
649
|
-
|
|
650
|
-
def evaluateWith(node, sphinxContext):
|
|
651
|
-
# covered clauses of withExpr match uncovered aspects of expr
|
|
652
|
-
hsBindings = sphinxContext.hyperspaceBindings
|
|
653
|
-
withRestrictionBinding = hsBindings.nodeBinding(node.restrictionExpr, isWithRestrictionNode=True)
|
|
654
|
-
hsBindings.withRestrictionBindings.append(withRestrictionBinding)
|
|
655
|
-
try:
|
|
656
|
-
for varAssignNode in node.variableAssignments:
|
|
657
|
-
evaluateVariableAssignment(varAssignNode, sphinxContext)
|
|
658
|
-
result = evaluate(node.bodyExpr, sphinxContext)
|
|
659
|
-
except Exception as ex:
|
|
660
|
-
del hsBindings.withRestrictionBindings[-1]
|
|
661
|
-
raise ex # re-throw the exception after removing withstack entry
|
|
662
|
-
del hsBindings.withRestrictionBindings[-1]
|
|
663
|
-
return result
|
|
664
|
-
|
|
665
|
-
def contextView(sphinxContext, fact=None):
|
|
666
|
-
if isinstance(fact, ModelFact):
|
|
667
|
-
return "{0}[{1}]".format(fact.qname,
|
|
668
|
-
", ".join("{2}={1}".format(aspectName(aspect),
|
|
669
|
-
factAspectValue(fact, aspect, view=True))
|
|
670
|
-
for aspect, fact in sphinxContext.hyperspaceBindings.aspectBoundFacts.items()
|
|
671
|
-
if factAspectValue(fact, aspect) and aspect != Aspect.CONCEPT))
|
|
672
|
-
else:
|
|
673
|
-
return "[{0}]".format(", ".join("{0}={1}".format(aspectName(aspect),
|
|
674
|
-
factAspectValue(fact, aspect, view=True))
|
|
675
|
-
for aspect, fact in sphinxContext.hyperspaceBindings.aspectBoundFacts.items()
|
|
676
|
-
if factAspectValue(fact, aspect)))
|
|
677
|
-
|
|
678
|
-
def aspectName(aspect):
|
|
679
|
-
if isinstance(aspect, QName):
|
|
680
|
-
return aspect
|
|
681
|
-
return {Aspect.LOCATION: "tuple",
|
|
682
|
-
Aspect.CONCEPT: "primary",
|
|
683
|
-
Aspect.ENTITY_IDENTIFIER: "entity",
|
|
684
|
-
Aspect.PERIOD: "period",
|
|
685
|
-
Aspect.UNIT: "unit",
|
|
686
|
-
Aspect.NON_XDT_SEGMENT: "segment",
|
|
687
|
-
Aspect.NON_XDT_SCENARIO: "scenario",
|
|
688
|
-
}.get(aspect)
|
|
689
|
-
if aspect in Aspect.label:
|
|
690
|
-
return Aspect.label[aspect]
|
|
691
|
-
else:
|
|
692
|
-
return str(aspect)
|
|
693
|
-
|
|
694
|
-
def factAspectValue(fact, aspect, view=False):
|
|
695
|
-
if fact is DEFAULT:
|
|
696
|
-
return 'none'
|
|
697
|
-
elif fact is NONDEFAULT:
|
|
698
|
-
return '*'
|
|
699
|
-
elif fact is DEFAULTorNONDEFAULT:
|
|
700
|
-
return '**'
|
|
701
|
-
elif aspect == Aspect.LOCATION:
|
|
702
|
-
parentQname = fact.getparent().qname
|
|
703
|
-
if parentQname == XbrlConst.qnXbrliXbrl: # not tuple
|
|
704
|
-
return NONE
|
|
705
|
-
return parentQname # tuple
|
|
706
|
-
elif aspect == Aspect.CONCEPT:
|
|
707
|
-
return fact.qname
|
|
708
|
-
elif fact.isTuple or fact.context is None:
|
|
709
|
-
return NONE #subsequent aspects don't exist for tuples
|
|
710
|
-
elif aspect == Aspect.UNIT:
|
|
711
|
-
if fact.unit is None:
|
|
712
|
-
return NONE
|
|
713
|
-
measures = fact.unit.measures
|
|
714
|
-
if measures[1]:
|
|
715
|
-
return "{0} / {1}".format(' '.join(str(m) for m in measures[0]),
|
|
716
|
-
' '.join(str(m) for m in measures[1]))
|
|
717
|
-
else:
|
|
718
|
-
return ' '.join(str(m) for m in measures[0])
|
|
719
|
-
else:
|
|
720
|
-
context = fact.context
|
|
721
|
-
if aspect == Aspect.PERIOD:
|
|
722
|
-
return ("forever" if context.isForeverPeriod else
|
|
723
|
-
XmlUtil.dateunionValue(context.instantDatetime, subtractOneDay=True) if context.isInstantPeriod else
|
|
724
|
-
XmlUtil.dateunionValue(context.startDatetime) + "-" + XmlUtil.dateunionValue(context.endDatetime, subtractOneDay=True))
|
|
725
|
-
elif aspect == Aspect.ENTITY_IDENTIFIER:
|
|
726
|
-
if view:
|
|
727
|
-
return context.entityIdentifier[1]
|
|
728
|
-
else:
|
|
729
|
-
return context.entityIdentifier # (scheme, identifier)
|
|
730
|
-
elif aspect in (Aspect.COMPLETE_SEGMENT, Aspect.COMPLETE_SCENARIO,
|
|
731
|
-
Aspect.NON_XDT_SEGMENT, Aspect.NON_XDT_SCENARIO):
|
|
732
|
-
return ''.join(XmlUtil.xmlstring(elt, stripXmlns=True, prettyPrint=True)
|
|
733
|
-
for elt in context.nonDimValues(aspect))
|
|
734
|
-
elif aspect == Aspect.DIMENSIONS:
|
|
735
|
-
return context.dimAspects(fact.xpCtx.defaultDimensionAspects)
|
|
736
|
-
elif isinstance(aspect, QName):
|
|
737
|
-
dimValue = context.dimValue(aspect)
|
|
738
|
-
if dimValue is None:
|
|
739
|
-
return NONE
|
|
740
|
-
else:
|
|
741
|
-
if isinstance(dimValue, QName): #default dim
|
|
742
|
-
return dimValue
|
|
743
|
-
elif dimValue.isExplicit:
|
|
744
|
-
return dimValue.memberQname
|
|
745
|
-
else: # explicit
|
|
746
|
-
return dimValue.typedMember.xValue # typed element value
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
evaluator = {
|
|
751
|
-
"astAnnotationDeclaration": evaluateAnnotationDeclaration,
|
|
752
|
-
"astBinaryOperation": evaluateBinaryOperation,
|
|
753
|
-
"astComment": evaluateNoOp,
|
|
754
|
-
"astFor": evaluateFor,
|
|
755
|
-
"astFormulaRule": evaluateRule,
|
|
756
|
-
"astFunctionDeclaration": evaluateFunctionDeclaration,
|
|
757
|
-
"astFunctionReference": evaluateFunctionReference,
|
|
758
|
-
"astHyperspaceExpression": evaluateHyperspaceExpression,
|
|
759
|
-
"astIf": evaluateIf,
|
|
760
|
-
"astMessage": evaluateMessage,
|
|
761
|
-
"astMethodReference": evaluateMethodReference,
|
|
762
|
-
"astNamespaceDeclaration": evaluateNoOp,
|
|
763
|
-
"astNode": evaluateNoOp,
|
|
764
|
-
"astNoOp": evaluateNoOp,
|
|
765
|
-
"astNumericLiteral": evaluateNumericLiteral,
|
|
766
|
-
"astPreconditionDeclaration": evaluatePreconditionDeclaration,
|
|
767
|
-
"astQnameLiteral": evaluateQnameLiteral,
|
|
768
|
-
"astReportRule": evaluateRule,
|
|
769
|
-
"astSourceFile": evaluateNoOp,
|
|
770
|
-
"astRuleBasePrecondition": evaluateRuleBasePrecondition,
|
|
771
|
-
"astPreconditionReference": evaluatePreconditionReference,
|
|
772
|
-
"astStringLiteral": evaluateStringLiteral,
|
|
773
|
-
"astTagAssignment": evaluateTagAssignment,
|
|
774
|
-
"astTagReference": evaluateTagReference,
|
|
775
|
-
"astValidationRule": evaluateRule,
|
|
776
|
-
"astValuesIteration": evaluateValuesIteration,
|
|
777
|
-
"astVariableAssignment": evaluateVariableAssignment,
|
|
778
|
-
"astVariableReference": evaluateVariableReference,
|
|
779
|
-
"astUnaryOperation": evaluateUnaryOperation,
|
|
780
|
-
"astWith": evaluateWith,
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
SphinxMethodsModuleInit()
|