arelle-release 2.36.26__py3-none-any.whl → 2.36.28__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arelle-release might be problematic. Click here for more details.
- arelle/ModelInstanceObject.py +3 -0
- arelle/_version.py +2 -2
- arelle/oim/Load.py +2 -2
- arelle/plugin/saveHtmlEBAtables.py +290 -215
- arelle/plugin/validate/ESEF/ESEF_Current/DTS.py +2 -2
- arelle/utils/PluginHooks.py +27 -0
- {arelle_release-2.36.26.dist-info → arelle_release-2.36.28.dist-info}/METADATA +1 -1
- {arelle_release-2.36.26.dist-info → arelle_release-2.36.28.dist-info}/RECORD +16 -15
- {arelle_release-2.36.26.dist-info → arelle_release-2.36.28.dist-info}/WHEEL +1 -1
- tests/integration_tests/scripts/tests/eba_tablesets.py +119 -0
- tests/integration_tests/ui_tests/ArelleGUITest/ArelleGUITest/ArelleGUITest.csproj +2 -2
- tests/integration_tests/validation/conformance_suite_configurations/efm_current.py +2 -7
- tests/resources/conformance_suites_timing/efm_current.json +8583 -8385
- {arelle_release-2.36.26.dist-info → arelle_release-2.36.28.dist-info}/LICENSE.md +0 -0
- {arelle_release-2.36.26.dist-info → arelle_release-2.36.28.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.36.26.dist-info → arelle_release-2.36.28.dist-info}/top_level.txt +0 -0
arelle/ModelInstanceObject.py
CHANGED
|
@@ -428,6 +428,9 @@ class ModelFact(ModelObject):
|
|
|
428
428
|
# non-numeric fact at this point
|
|
429
429
|
if len(val) == 0: # zero length string for HMRC fixed fact
|
|
430
430
|
return "(reported)"
|
|
431
|
+
if self.xValid >= VALID and isinstance(self.xValue, str):
|
|
432
|
+
# Prefer the xs:whiteSpace normalized version of strings
|
|
433
|
+
return self.xValue
|
|
431
434
|
return val
|
|
432
435
|
except Exception as ex:
|
|
433
436
|
return str(ex) # could be transform value of inline fact
|
arelle/_version.py
CHANGED
arelle/oim/Load.py
CHANGED
|
@@ -1608,6 +1608,8 @@ def _loadFromOIM(cntlr, error, warning, modelXbrl, oimFile, mappedUri):
|
|
|
1608
1608
|
(tableDimensions, "table dimension"),
|
|
1609
1609
|
(reportDimensions, "report dimension")):
|
|
1610
1610
|
for dimName, dimValue in inheritedDims.items():
|
|
1611
|
+
if dimSource.startswith("propertyGroup"):
|
|
1612
|
+
factDimensionPropGrpCol[dimName] = propGroupDimSource[dimName]
|
|
1611
1613
|
if dimName not in colFactDims and dimName not in noValueDimNames:
|
|
1612
1614
|
dimValue = inheritedDims[dimName]
|
|
1613
1615
|
dimAttr = None
|
|
@@ -1651,8 +1653,6 @@ def _loadFromOIM(cntlr, error, warning, modelXbrl, oimFile, mappedUri):
|
|
|
1651
1653
|
noValueDimNames.add(dimName)
|
|
1652
1654
|
else:
|
|
1653
1655
|
colFactDims[dimName] = dimValue
|
|
1654
|
-
if dimSource.startswith("propertyGroup"):
|
|
1655
|
-
factDimensionPropGrpCol[dimName] = propGroupDimSource[dimName]
|
|
1656
1656
|
if factDecimals.get(colName) is not None:
|
|
1657
1657
|
dimValue = factDecimals[colName]
|
|
1658
1658
|
dimSource = "column decimals"
|
|
@@ -1,105 +1,222 @@
|
|
|
1
|
-
|
|
1
|
+
"""
|
|
2
2
|
Save HTML EBA Tables is an example of a plug-in to both GUI menu and command line/web service
|
|
3
3
|
that will save a directory containing HTML Tablesets with an EBA index page.
|
|
4
4
|
|
|
5
5
|
See COPYRIGHT.md for copyright information.
|
|
6
|
-
|
|
7
|
-
from arelle.Version import authorLabel, copyrightLabel
|
|
6
|
+
"""
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
import os
|
|
9
|
+
import threading
|
|
10
|
+
from operator import itemgetter
|
|
11
|
+
from optparse import OptionParser
|
|
12
|
+
from tkinter import Menu
|
|
13
|
+
from typing import Any
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
from lxml import etree
|
|
16
|
+
|
|
17
|
+
from arelle import Version, XbrlConst, XmlUtil
|
|
18
|
+
from arelle.CntlrCmdLine import CntlrCmdLine
|
|
19
|
+
from arelle.CntlrWinMain import CntlrWinMain
|
|
20
|
+
from arelle.ModelDocument import Type
|
|
21
|
+
from arelle.ModelObjectFactory import parser
|
|
22
|
+
from arelle.ModelRenderingObject import DefnMdlTable
|
|
23
|
+
from arelle.ModelXbrl import ModelXbrl
|
|
24
|
+
from arelle.rendering import RenderingEvaluator
|
|
25
|
+
from arelle.RuntimeOptions import RuntimeOptions
|
|
26
|
+
from arelle.typing import TypeGetText
|
|
27
|
+
from arelle.utils.PluginHooks import PluginHooks
|
|
28
|
+
from arelle.ViewFileRenderedGrid import viewRenderedGrid
|
|
29
|
+
|
|
30
|
+
_: TypeGetText
|
|
31
|
+
|
|
32
|
+
MENU_HTML = """<!DOCTYPE html>
|
|
33
|
+
<html>
|
|
34
|
+
<head>
|
|
35
|
+
<style>
|
|
36
|
+
body {
|
|
37
|
+
margin: 0;
|
|
38
|
+
padding: 10px;
|
|
39
|
+
font-family: Arial, sans-serif;
|
|
40
|
+
color: #243e5e;
|
|
41
|
+
}
|
|
42
|
+
.nav-list-menu-ul {
|
|
43
|
+
list-style-type: none;
|
|
44
|
+
padding: 0;
|
|
45
|
+
margin: 0;
|
|
46
|
+
}
|
|
47
|
+
.nav-list-menu-li {
|
|
48
|
+
margin: 5px 0;
|
|
49
|
+
padding: 5px;
|
|
50
|
+
border-bottom: 1px solid #eee;
|
|
51
|
+
}
|
|
52
|
+
.nav-list-menu-link {
|
|
53
|
+
text-decoration: none;
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
display: block;
|
|
56
|
+
background: none;
|
|
57
|
+
border: none;
|
|
58
|
+
padding: 0;
|
|
59
|
+
}
|
|
60
|
+
.nav-list-menu-link:hover {
|
|
61
|
+
text-decoration: underline;
|
|
62
|
+
}
|
|
63
|
+
</style>
|
|
64
|
+
</head>
|
|
65
|
+
<body>
|
|
66
|
+
<ul class="nav-list-menu-ul"/>
|
|
67
|
+
</body>
|
|
68
|
+
</html>
|
|
69
|
+
"""
|
|
17
70
|
|
|
18
|
-
|
|
19
|
-
<html
|
|
20
|
-
<head
|
|
21
|
-
<
|
|
71
|
+
CENTER_LANDING_HTML = """<!DOCTYPE html>
|
|
72
|
+
<html>
|
|
73
|
+
<head>
|
|
74
|
+
<style>
|
|
75
|
+
body {
|
|
76
|
+
margin: 0;
|
|
77
|
+
padding: 20px;
|
|
78
|
+
font-family: Arial, sans-serif;
|
|
79
|
+
}
|
|
80
|
+
#page-title {
|
|
81
|
+
margin-bottom: 20px;
|
|
82
|
+
}
|
|
83
|
+
#page-title h1 {
|
|
84
|
+
color: #243e5e;
|
|
85
|
+
margin-top: 0;
|
|
86
|
+
}
|
|
87
|
+
#content-center {
|
|
88
|
+
margin-top: 20px;
|
|
89
|
+
line-height: 1.5;
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
22
92
|
</head>
|
|
23
|
-
<body
|
|
24
|
-
|
|
93
|
+
<body>
|
|
94
|
+
<div id="page-title">
|
|
95
|
+
<h1>Taxonomy Tables Viewer</h1>
|
|
96
|
+
</div>
|
|
97
|
+
<div id="content-center">
|
|
98
|
+
<p>Please select tables to view by clicking in the left column.</p>
|
|
99
|
+
</div>
|
|
100
|
+
</body>
|
|
101
|
+
</html>
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
TABLE_CSS_EXTRAS = """
|
|
105
|
+
table {background:#fff}
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def indexFileHTML(indexBaseName: str) -> str:
|
|
110
|
+
return f'''<!DOCTYPE html>
|
|
111
|
+
<html>
|
|
112
|
+
<head>
|
|
113
|
+
<meta charset="utf-8">
|
|
114
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
115
|
+
<title>EBA - Tablesets</title>
|
|
116
|
+
<style>
|
|
117
|
+
html, body {{
|
|
118
|
+
margin: 0;
|
|
119
|
+
padding: 0;
|
|
120
|
+
height: 100%;
|
|
121
|
+
width: 100%;
|
|
122
|
+
font-family: Arial, sans-serif;
|
|
123
|
+
display: flex;
|
|
124
|
+
flex-direction: column;
|
|
125
|
+
}}
|
|
126
|
+
#header {{
|
|
127
|
+
background: rgb(36, 62, 94);
|
|
128
|
+
color: rgb(255, 255, 255);
|
|
129
|
+
height: 40px;
|
|
130
|
+
}}
|
|
131
|
+
#header h1 {{
|
|
132
|
+
font-size: 1.5em;
|
|
133
|
+
margin: 0.25em;
|
|
134
|
+
}}
|
|
135
|
+
#main-container {{
|
|
136
|
+
display: flex;
|
|
137
|
+
flex: 1;
|
|
138
|
+
height: calc(100vh - 40px);
|
|
139
|
+
}}
|
|
140
|
+
#menu-container {{
|
|
141
|
+
width: 360px;
|
|
142
|
+
border-right: 2px solid #243e5e;
|
|
143
|
+
overflow-y: auto;
|
|
144
|
+
box-sizing: border-box;
|
|
145
|
+
}}
|
|
146
|
+
#content-container {{
|
|
147
|
+
flex: 1;
|
|
148
|
+
overflow: auto;
|
|
149
|
+
box-sizing: border-box;
|
|
150
|
+
}}
|
|
151
|
+
iframe {{
|
|
152
|
+
border: none;
|
|
153
|
+
width: 100%;
|
|
154
|
+
height: 100%;
|
|
155
|
+
}}
|
|
156
|
+
</style>
|
|
157
|
+
<script>
|
|
158
|
+
function loadContent(url) {{
|
|
159
|
+
document.getElementById('content-frame').src = url;
|
|
160
|
+
}}
|
|
161
|
+
</script>
|
|
162
|
+
</head>
|
|
163
|
+
<body>
|
|
164
|
+
<div id="header"><h1>EBA - Tablesets</h1></div>
|
|
165
|
+
<div id="main-container">
|
|
166
|
+
<div id="menu-container">
|
|
167
|
+
<iframe src="{indexBaseName}FormsFrame.html" width="100%" height="100%" frameborder="0" id="menu-frame"></iframe>
|
|
168
|
+
</div>
|
|
169
|
+
<div id="content-container">
|
|
170
|
+
<iframe src="{indexBaseName}CenterLanding.html" width="100%" height="100%" frameborder="0" id="content-frame"></iframe>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
25
173
|
</body>
|
|
26
174
|
</html>
|
|
27
175
|
'''
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class nonTkBooleanVar():
|
|
39
|
-
def __init__(self, value=True):
|
|
40
|
-
self.value = value
|
|
41
|
-
def set(self, value):
|
|
42
|
-
self.value = value
|
|
43
|
-
def get(self):
|
|
44
|
-
return self.value
|
|
45
|
-
|
|
46
|
-
class View():
|
|
47
|
-
def __init__(self, tableOrELR, ignoreDimValidity, xAxisChildrenFirst, yAxisChildrenFirst):
|
|
48
|
-
self.tblELR = tableOrELR
|
|
49
|
-
# context menu boolean vars (non-tkinter boolean
|
|
50
|
-
self.ignoreDimValidity = nonTkBooleanVar(value=ignoreDimValidity)
|
|
51
|
-
self.xAxisChildrenFirst = nonTkBooleanVar(value=xAxisChildrenFirst)
|
|
52
|
-
self.yAxisChildrenFirst = nonTkBooleanVar(value=yAxisChildrenFirst)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def generateHtmlEbaTablesetFiles(dts: ModelXbrl, indexFile: str, lang: str = "en") -> None:
|
|
179
|
+
try:
|
|
180
|
+
numTableFiles = 0
|
|
181
|
+
_parser = parser(dts, None)[0]
|
|
182
|
+
menuFrameDocument = etree.fromstring(MENU_HTML, parser=_parser, base_url=indexFile)
|
|
183
|
+
listElt = menuFrameDocument.find(".//ul")
|
|
184
|
+
assert listElt is not None, "No list element in index document"
|
|
53
185
|
|
|
54
186
|
indexBase = indexFile.rpartition(".")[0]
|
|
55
187
|
groupTableRels = dts.modelXbrl.relationshipSet(XbrlConst.euGroupTable)
|
|
56
188
|
modelTables = []
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
table {background:#fff}
|
|
60
|
-
'''
|
|
61
|
-
# order number is missing
|
|
62
|
-
def viewTable(modelTable):
|
|
189
|
+
|
|
190
|
+
def viewTable(modelTable: DefnMdlTable) -> None:
|
|
63
191
|
if modelTable is None:
|
|
64
192
|
return
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
dts.modelManager.cntlr.addToLog("viewing: " +
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
tableName = modelTable.id
|
|
193
|
+
tableId = modelTable.id or ""
|
|
194
|
+
if isinstance(modelTable, DefnMdlTable):
|
|
195
|
+
dts.modelManager.cntlr.addToLog("viewing: " + tableId)
|
|
196
|
+
tblFile = os.path.join(os.path.dirname(indexFile), tableId + ".html")
|
|
197
|
+
tableName = tableId
|
|
71
198
|
if tableName.startswith("eba_t"):
|
|
72
199
|
tableName = tableName.removeprefix("eba_t")
|
|
73
|
-
|
|
200
|
+
elif tableName.startswith("srb_t"):
|
|
74
201
|
tableName = tableName.removeprefix("srb_t")
|
|
75
|
-
viewRenderedGrid(dts,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
# generaate menu entry
|
|
82
|
-
elt = etree.SubElement(listElt, "{http://www.w3.org/1999/xhtml}li")
|
|
83
|
-
elt.set("class", "CMSListMenuLI")
|
|
84
|
-
elt.set("id", modelTable.id)
|
|
85
|
-
elt = etree.SubElement(elt, "{http://www.w3.org/1999/xhtml}a")
|
|
202
|
+
viewRenderedGrid(dts, tblFile, lang=lang, cssExtras=TABLE_CSS_EXTRAS, table=tableName) # type: ignore[no-untyped-call]
|
|
203
|
+
|
|
204
|
+
elt = etree.SubElement(listElt, "li")
|
|
205
|
+
elt.set("class", "nav-list-menu-li")
|
|
206
|
+
elt.set("id", tableId)
|
|
207
|
+
elt = etree.SubElement(elt, "button")
|
|
86
208
|
elt.text = modelTable.genLabel(lang=lang, strip=True)
|
|
87
|
-
elt.set("class", "
|
|
88
|
-
elt.set("
|
|
89
|
-
elt.set("onClick", "javascript:parent.body.location.href='{0}';".format(modelTable.id + ".html"))
|
|
209
|
+
elt.set("class", "nav-list-menu-link")
|
|
210
|
+
elt.set("onClick", f"javascript:parent.loadContent('{tableId}.html');")
|
|
90
211
|
elt.text = modelTable.genLabel(lang=lang, strip=True)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
elt = etree.SubElement(listElt, "{http://www.w3.org/1999/xhtml}li")
|
|
95
|
-
elt.set("class", "CMSListMenuLink")
|
|
96
|
-
elt.set("id", modelTable.id)
|
|
212
|
+
else:
|
|
213
|
+
elt = etree.SubElement(listElt, "li")
|
|
214
|
+
elt.set("id", tableId)
|
|
97
215
|
elt.text = modelTable.label(lang=lang, strip=True)
|
|
98
216
|
|
|
99
217
|
for rel in groupTableRels.fromModelObject(modelTable):
|
|
100
218
|
viewTable(rel.toModelObject)
|
|
101
219
|
|
|
102
|
-
|
|
103
220
|
for rootConcept in groupTableRels.rootConcepts:
|
|
104
221
|
sourceline = 0
|
|
105
222
|
for rel in dts.modelXbrl.relationshipSet(XbrlConst.euGroupTable).fromModelObject(rootConcept):
|
|
@@ -107,171 +224,129 @@ table {background:#fff}
|
|
|
107
224
|
break
|
|
108
225
|
modelTables.append((rootConcept, sourceline))
|
|
109
226
|
|
|
110
|
-
for modelTable,
|
|
227
|
+
for modelTable, _order in sorted(modelTables, key=itemgetter(1)):
|
|
111
228
|
viewTable(modelTable)
|
|
112
229
|
|
|
113
|
-
with open(indexBase + "FormsFrame.html", "
|
|
114
|
-
XmlUtil.writexml(fh,
|
|
230
|
+
with open(indexBase + "FormsFrame.html", "w", encoding="utf-8") as fh:
|
|
231
|
+
XmlUtil.writexml(fh, menuFrameDocument, encoding="utf-8")
|
|
115
232
|
|
|
116
|
-
with open(indexFile, "
|
|
117
|
-
fh.write(
|
|
118
|
-
'''
|
|
119
|
-
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
120
|
-
<head id="Head1">
|
|
121
|
-
<title>European Banking Authority - EBA - FINREP Taxonomy</title>
|
|
122
|
-
<meta name="generator" content="Arelle(r) {0}" />
|
|
123
|
-
<meta name="provider" content="Aguilonius(r)" />
|
|
124
|
-
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
|
|
125
|
-
<meta http-equiv="pragma" content="no-cache" />
|
|
126
|
-
<meta http-equiv="content-style-type" content="text/css" />
|
|
127
|
-
<meta http-equiv="content-script-type" content="text/javascript" />
|
|
128
|
-
<link type="text/css" rel="stylesheet" href="http://arelle.org/files/EBA/style20121210/eba.css" />
|
|
129
|
-
</head>
|
|
130
|
-
<frameset border="0" frameborder="0" rows="90,*">
|
|
131
|
-
<frame name="head" src="{1}" scrolling="no" marginwidth="0" marginheight="10"/>
|
|
132
|
-
<frameset bordercolor="#0000cc" border="10" frameborder="no" framespacing="0" cols="360, *">
|
|
133
|
-
<frame src="{2}" name="menu" bordercolor="#0000cc"/>
|
|
134
|
-
<frame src="{3}" name="body" bordercolor="#0000cc"/>
|
|
135
|
-
</frameset>
|
|
136
|
-
</frameset>
|
|
137
|
-
'''.format(Version.version,
|
|
138
|
-
os.path.basename(indexBase) + "TopFrame.html",
|
|
139
|
-
os.path.basename(indexBase) + "FormsFrame.html",
|
|
140
|
-
os.path.basename(indexBase) + "CenterLanding.html",
|
|
141
|
-
))
|
|
142
|
-
|
|
143
|
-
with open(indexBase + "TopFrame.html", "wt", encoding="utf-8") as fh:
|
|
144
|
-
fh.write(
|
|
145
|
-
'''
|
|
146
|
-
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
147
|
-
<head id="Top">
|
|
148
|
-
<link type="text/css" rel="stylesheet" href="http://arelle.org/files/EBA/style20121210/eba.css" />
|
|
149
|
-
</head>
|
|
150
|
-
<body class="LTR IE7 ENGB">
|
|
151
|
-
<div id="topsection">
|
|
152
|
-
<div id="topsectionLeft" style="cursor:pointer;" onclick="location.href='http://www.eba.europa.eu/home.aspx';"></div>
|
|
153
|
-
<div id="topsectionRight"></div>
|
|
154
|
-
<div id="topnavigation">
|
|
155
|
-
<ul id="menuElem">
|
|
156
|
-
<li><a href="http://www.eba.europa.eu/topnav/Contacts.aspx">Contacts</a></li>
|
|
157
|
-
<li><a href="http://www.eba.europa.eu/topnav/Links.aspx">Links</a></li>
|
|
158
|
-
<li><a href="http://www.eba.europa.eu/topnav/Sitemap.aspx">Sitemap</a></li>
|
|
159
|
-
<li><a href="http://www.eba.europa.eu/topnav/Legal-Notice.aspx">Legal Notice</a></li>
|
|
160
|
-
</ul>
|
|
161
|
-
</div>
|
|
162
|
-
</body>
|
|
163
|
-
</html>
|
|
164
|
-
''')
|
|
165
|
-
|
|
166
|
-
with open(indexBase + "CenterLanding.html", "wt", encoding="utf-8") as fh:
|
|
167
|
-
fh.write(
|
|
168
|
-
'''
|
|
169
|
-
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
170
|
-
<head id="Center">
|
|
171
|
-
<link type="text/css" rel="stylesheet" href="http://http://arelle.org/files/EBA/style20121210/eba.css" />
|
|
172
|
-
</head>
|
|
173
|
-
<body class="LTR IE7 ENGB">
|
|
174
|
-
<div id="plc_lt_zoneContent_usercontrol_userControlElem_ContentPanel">
|
|
175
|
-
<div id="plc_lt_zoneContent_usercontrol_userControlElem_PanelTitle">
|
|
176
|
-
<div id="pagetitle" style="float:left;width:500px;">
|
|
177
|
-
<h1>Taxonomy Tables Viewer</h1>
|
|
178
|
-
</div>
|
|
179
|
-
</div>
|
|
180
|
-
</div>
|
|
181
|
-
<div style="clear:both;"></div>
|
|
182
|
-
<div id="contentcenter">
|
|
183
|
-
<p style="text-align: justify; margin-top: 0pt; margin-bottom: 0pt">Please select tables to view by clicking in the left column.</p>
|
|
184
|
-
</div>
|
|
185
|
-
</body>
|
|
186
|
-
</html>
|
|
187
|
-
''')
|
|
233
|
+
with open(indexFile, "w", encoding="utf-8") as fh:
|
|
234
|
+
fh.write(indexFileHTML(os.path.basename(indexBase)))
|
|
188
235
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
#zf = zipfile.ZipFile(__file__.rpartition('.')[0] + "Files.zip", mode="r")
|
|
192
|
-
#zf.extractall(path=os.path.dirname(indexBase))
|
|
193
|
-
#zf.close()
|
|
236
|
+
with open(indexBase + "CenterLanding.html", "w", encoding="utf-8") as fh:
|
|
237
|
+
fh.write(CENTER_LANDING_HTML)
|
|
194
238
|
|
|
195
|
-
dts.info(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
239
|
+
dts.info(
|
|
240
|
+
"info:saveEBAtables",
|
|
241
|
+
_("Tables index file of %(entryFile)s has %(numberTableFiles)s table files with index file %(indexFile)s."),
|
|
242
|
+
modelObject=dts,
|
|
243
|
+
entryFile=dts.uri,
|
|
244
|
+
numberTableFiles=numTableFiles,
|
|
245
|
+
indexFile=indexFile,
|
|
246
|
+
)
|
|
199
247
|
|
|
200
248
|
dts.modelManager.showStatus(_("Saved EBA HTML Table Files"), 5000)
|
|
201
249
|
except Exception as ex:
|
|
202
|
-
dts.error(
|
|
203
|
-
|
|
250
|
+
dts.error(
|
|
251
|
+
"exception",
|
|
252
|
+
_("HTML EBA Tableset files generation exception: %(error)s"),
|
|
253
|
+
error=ex,
|
|
204
254
|
modelXbrl=dts,
|
|
205
|
-
exc_info=True
|
|
255
|
+
exc_info=True,
|
|
256
|
+
)
|
|
206
257
|
|
|
207
|
-
def saveHtmlEbaTablesMenuEntender(cntlr, menu, *args, **kwargs):
|
|
208
|
-
# Extend menu with an item for the save infoset plugin
|
|
209
|
-
menu.add_command(label="Save HTML EBA Tables",
|
|
210
|
-
underline=0,
|
|
211
|
-
command=lambda: saveHtmlEbaTablesMenuCommand(cntlr) )
|
|
212
258
|
|
|
213
|
-
def saveHtmlEbaTablesMenuCommand(cntlr):
|
|
214
|
-
# save Infoset menu item has been invoked
|
|
215
|
-
from arelle.ModelDocument import Type
|
|
259
|
+
def saveHtmlEbaTablesMenuCommand(cntlr: CntlrWinMain) -> None:
|
|
216
260
|
if cntlr.modelManager is None or cntlr.modelManager.modelXbrl is None:
|
|
217
|
-
cntlr.addToLog("No DTS loaded.")
|
|
261
|
+
cntlr.addToLog("No DTS loaded.") # type: ignore[no-untyped-call]
|
|
218
262
|
return
|
|
219
263
|
|
|
220
|
-
|
|
221
|
-
indexFile = cntlr.uiFileDialog(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
264
|
+
assert cntlr.config is not None
|
|
265
|
+
indexFile = cntlr.uiFileDialog( # type: ignore[no-untyped-call]
|
|
266
|
+
"save",
|
|
267
|
+
title=_("arelle - Save HTML EBA Tables Index file"),
|
|
268
|
+
initialdir=cntlr.config.setdefault("htmlEbaTablesFileDir", "."),
|
|
269
|
+
filetypes=[(_("HTML index file .html"), "*.html")],
|
|
270
|
+
defaultextension=".html",
|
|
271
|
+
)
|
|
272
|
+
if not isinstance(indexFile, str):
|
|
273
|
+
return
|
|
229
274
|
cntlr.config["htmlEbaTablesFileDir"] = os.path.dirname(indexFile)
|
|
230
275
|
cntlr.saveConfig()
|
|
231
276
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
277
|
+
thread = threading.Thread(
|
|
278
|
+
target=lambda _dts=cntlr.modelManager.modelXbrl, _indexFile=indexFile: generateHtmlEbaTablesetFiles(
|
|
279
|
+
_dts, _indexFile
|
|
280
|
+
)
|
|
281
|
+
)
|
|
237
282
|
thread.daemon = True
|
|
238
283
|
thread.start()
|
|
239
284
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
285
|
+
|
|
286
|
+
class SaveHtmlEbaTablesPlugin(PluginHooks):
|
|
287
|
+
@staticmethod
|
|
288
|
+
def cntlrWinMainMenuTools(
|
|
289
|
+
cntlr: CntlrWinMain,
|
|
290
|
+
menu: Menu,
|
|
291
|
+
*args: Any,
|
|
292
|
+
**kwargs: Any,
|
|
293
|
+
) -> None:
|
|
294
|
+
menu.add_command(label="Save HTML EBA Tables", underline=0, command=lambda: saveHtmlEbaTablesMenuCommand(cntlr))
|
|
295
|
+
|
|
296
|
+
@staticmethod
|
|
297
|
+
def cntlrCmdLineOptions(
|
|
298
|
+
parser: OptionParser,
|
|
299
|
+
*args: Any,
|
|
300
|
+
**kwargs: Any,
|
|
301
|
+
) -> None:
|
|
302
|
+
parser.add_option(
|
|
303
|
+
"--save-EBA-tablesets",
|
|
304
|
+
action="store",
|
|
305
|
+
dest="ebaTablesetIndexFile",
|
|
306
|
+
help=_("Save HTML EBA Tablesets index file with provided filename."),
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
@staticmethod
|
|
310
|
+
def cntlrCmdLineXbrlLoaded(
|
|
311
|
+
cntlr: CntlrCmdLine,
|
|
312
|
+
options: RuntimeOptions,
|
|
313
|
+
modelXbrl: ModelXbrl,
|
|
314
|
+
*args: Any,
|
|
315
|
+
**kwargs: Any,
|
|
316
|
+
) -> None:
|
|
317
|
+
ebaTablesetIndexFile = getattr(options, "ebaTablesetIndexFile", None)
|
|
318
|
+
modelDocType = getattr(modelXbrl.modelDocument, "type", None)
|
|
319
|
+
if ebaTablesetIndexFile == "generateEBAFiles" and modelDocType in (Type.TESTCASESINDEX, Type.TESTCASE):
|
|
320
|
+
cntlr.modelManager.generateEBAFiles = True # type: ignore[attr-defined]
|
|
321
|
+
|
|
322
|
+
@staticmethod
|
|
323
|
+
def cntlrCmdLineXbrlRun(
|
|
324
|
+
cntlr: CntlrCmdLine,
|
|
325
|
+
options: RuntimeOptions,
|
|
326
|
+
modelXbrl: ModelXbrl,
|
|
327
|
+
*args: Any,
|
|
328
|
+
**kwargs: Any,
|
|
329
|
+
) -> None:
|
|
330
|
+
ebaTablesetIndexFile = getattr(options, "ebaTablesetIndexFile", None)
|
|
331
|
+
if ebaTablesetIndexFile is None or ebaTablesetIndexFile == "generateEBAFiles":
|
|
332
|
+
return
|
|
256
333
|
if cntlr.modelManager is None or cntlr.modelManager.modelXbrl is None:
|
|
257
334
|
cntlr.addToLog("No taxonomy loaded.")
|
|
258
335
|
return
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
RenderingEvaluator.init(modelXbrl)
|
|
262
|
-
generateHtmlEbaTablesetFiles(cntlr.modelManager.modelXbrl, options.ebaTablesetIndexFile)
|
|
336
|
+
RenderingEvaluator.init(modelXbrl) # type: ignore[no-untyped-call]
|
|
337
|
+
generateHtmlEbaTablesetFiles(cntlr.modelManager.modelXbrl, ebaTablesetIndexFile)
|
|
263
338
|
|
|
264
339
|
|
|
265
340
|
__pluginInfo__ = {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
341
|
+
"name": "Save HTML EBA Tables",
|
|
342
|
+
"version": "0.10",
|
|
343
|
+
"description": "This plug-in adds a feature to a directory containing HTML Tablesets with an EBA index page.",
|
|
344
|
+
"license": "Apache-2",
|
|
345
|
+
"author": Version.authorLabel,
|
|
346
|
+
"copyright": Version.copyrightLabel,
|
|
272
347
|
# classes of mount points (required)
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
348
|
+
"CntlrWinMain.Menu.Tools": SaveHtmlEbaTablesPlugin.cntlrWinMainMenuTools,
|
|
349
|
+
"CntlrCmdLine.Options": SaveHtmlEbaTablesPlugin.cntlrCmdLineOptions,
|
|
350
|
+
"CntlrCmdLine.Xbrl.Loaded": SaveHtmlEbaTablesPlugin.cntlrCmdLineXbrlLoaded,
|
|
351
|
+
"CntlrCmdLine.Xbrl.Run": SaveHtmlEbaTablesPlugin.cntlrCmdLineXbrlRun,
|
|
277
352
|
}
|
|
@@ -168,8 +168,8 @@ def checkFilingDTS(val: ValidateXbrl, modelDocument: ModelDocument, esefNotesCon
|
|
|
168
168
|
narrowerConcept = widerNarrowerRelSet.toModelObject(modelConcept)
|
|
169
169
|
|
|
170
170
|
# Transform the qname to str for the later join()
|
|
171
|
-
widerTypes = set(r.toModelObject.typeQname for r in widerConcept)
|
|
172
|
-
narrowerTypes = set(r.fromModelObject.typeQname for r in narrowerConcept)
|
|
171
|
+
widerTypes = set(r.toModelObject.typeQname for r in widerConcept if r.toModelObject is not None)
|
|
172
|
+
narrowerTypes = set(r.fromModelObject.typeQname for r in narrowerConcept if r.fromModelObject is not None)
|
|
173
173
|
|
|
174
174
|
if (narrowerTypes and narrowerTypes != {modelConcept.typeQname}) or (widerTypes and widerTypes != {modelConcept.typeQname}):
|
|
175
175
|
widerNarrowerType = "{} {}".format(
|
arelle/utils/PluginHooks.py
CHANGED
|
@@ -94,6 +94,33 @@ class PluginHooks(ABC):
|
|
|
94
94
|
"""
|
|
95
95
|
raise NotImplementedError
|
|
96
96
|
|
|
97
|
+
@staticmethod
|
|
98
|
+
def cntlrCmdLineXbrlLoaded(
|
|
99
|
+
cntlr: CntlrCmdLine,
|
|
100
|
+
options: RuntimeOptions,
|
|
101
|
+
modelXbrl: ModelXbrl,
|
|
102
|
+
entrypoint: dict[str, str] | None = None,
|
|
103
|
+
responseZipStream: BinaryIO | None = None,
|
|
104
|
+
*args: Any,
|
|
105
|
+
**kwargs: Any,
|
|
106
|
+
) -> None:
|
|
107
|
+
"""
|
|
108
|
+
Plugin hook: `CntlrCmdLine.Xbrl.Loaded`
|
|
109
|
+
|
|
110
|
+
This hook is triggered after loading, but prior to validation (if requested) and loading views.
|
|
111
|
+
It's useful if you need to perform operations with the XBRL model prior to rendering views.
|
|
112
|
+
|
|
113
|
+
:param cntlr: The [Cntlr](#arelle.Cntlr.Cntlr) being initialized.
|
|
114
|
+
:param options: Parsed options object.
|
|
115
|
+
:param modelXbrl: The loaded [ModelXbrl](#arelle.ModelXbrl.ModelXbrl).
|
|
116
|
+
:param entrypoint: The entrypoint that was parsed to load the model.
|
|
117
|
+
:param responseZipStream: The response zip stream if loaded from the webserver and the user requested a zip response.
|
|
118
|
+
:param args: Argument capture to ensure new parameters don't break plugin hook.
|
|
119
|
+
:param kwargs: Argument capture to ensure new named parameters don't break plugin hook.
|
|
120
|
+
:return: None
|
|
121
|
+
"""
|
|
122
|
+
raise NotImplementedError
|
|
123
|
+
|
|
97
124
|
@staticmethod
|
|
98
125
|
def cntlrCmdLineXbrlRun(
|
|
99
126
|
cntlr: CntlrCmdLine,
|