ixbrl-viewer 1.4.1__py3-none-any.whl → 1.4.86__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.
Files changed (190) hide show
  1. iXBRLViewerPlugin/__init__.py +231 -127
  2. iXBRLViewerPlugin/_version.py +33 -3
  3. iXBRLViewerPlugin/constants.py +96 -2
  4. iXBRLViewerPlugin/featureConfig.py +8 -1
  5. iXBRLViewerPlugin/iXBRLViewer.py +356 -214
  6. iXBRLViewerPlugin/plugin.py +12 -0
  7. iXBRLViewerPlugin/ui.py +81 -50
  8. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
  9. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js.LICENSE.txt +12 -5
  10. iXBRLViewerPlugin/viewer/i18next-parser.config.js +1 -1
  11. iXBRLViewerPlugin/viewer/src/data/utr.json +1244 -0
  12. iXBRLViewerPlugin/viewer/src/html/fact-details.html +69 -38
  13. iXBRLViewerPlugin/viewer/src/html/footer-logo.html +4 -0
  14. iXBRLViewerPlugin/viewer/src/html/footnote-details.html +2 -2
  15. iXBRLViewerPlugin/viewer/src/html/inspector.html +352 -197
  16. iXBRLViewerPlugin/viewer/src/i18n/cy/balancetypes.json +1 -0
  17. iXBRLViewerPlugin/viewer/src/i18n/cy/currencies.json +13 -0
  18. iXBRLViewerPlugin/viewer/src/i18n/cy/datatypes.json +9 -0
  19. iXBRLViewerPlugin/viewer/src/i18n/cy/labelroles.json +24 -0
  20. iXBRLViewerPlugin/viewer/src/i18n/cy/referenceparts.json +10 -0
  21. iXBRLViewerPlugin/viewer/src/i18n/cy/scale.json +16 -0
  22. iXBRLViewerPlugin/viewer/src/i18n/cy/tooltips.json +17 -0
  23. iXBRLViewerPlugin/viewer/src/i18n/cy/translation.json +179 -0
  24. iXBRLViewerPlugin/viewer/src/i18n/da/balancetypes.json +4 -0
  25. iXBRLViewerPlugin/viewer/src/i18n/da/currencies.json +13 -0
  26. iXBRLViewerPlugin/viewer/src/i18n/da/datatypes.json +9 -0
  27. iXBRLViewerPlugin/viewer/src/i18n/da/labelroles.json +24 -0
  28. iXBRLViewerPlugin/viewer/src/i18n/da/referenceparts.json +10 -0
  29. iXBRLViewerPlugin/viewer/src/i18n/da/scale.json +15 -0
  30. iXBRLViewerPlugin/viewer/src/i18n/da/tooltips.json +17 -0
  31. iXBRLViewerPlugin/viewer/src/i18n/da/translation.json +179 -0
  32. iXBRLViewerPlugin/viewer/src/i18n/de/balancetypes.json +4 -0
  33. iXBRLViewerPlugin/viewer/src/i18n/de/currencies.json +13 -0
  34. iXBRLViewerPlugin/viewer/src/i18n/de/datatypes.json +9 -0
  35. iXBRLViewerPlugin/viewer/src/i18n/de/labelroles.json +24 -0
  36. iXBRLViewerPlugin/viewer/src/i18n/de/referenceparts.json +10 -0
  37. iXBRLViewerPlugin/viewer/src/i18n/de/scale.json +15 -0
  38. iXBRLViewerPlugin/viewer/src/i18n/de/tooltips.json +17 -0
  39. iXBRLViewerPlugin/viewer/src/i18n/de/translation.json +179 -0
  40. iXBRLViewerPlugin/viewer/src/i18n/en/balancetypes.json +4 -0
  41. iXBRLViewerPlugin/viewer/src/i18n/en/datatypes.json +10 -0
  42. iXBRLViewerPlugin/viewer/src/i18n/en/labelroles.json +4 -0
  43. iXBRLViewerPlugin/viewer/src/i18n/en/scale.json +16 -0
  44. iXBRLViewerPlugin/viewer/src/i18n/en/tooltips.json +17 -0
  45. iXBRLViewerPlugin/viewer/src/i18n/en/translation.json +73 -23
  46. iXBRLViewerPlugin/viewer/src/i18n/es/balancetypes.json +4 -0
  47. iXBRLViewerPlugin/viewer/src/i18n/es/datatypes.json +10 -0
  48. iXBRLViewerPlugin/viewer/src/i18n/es/labelroles.json +24 -0
  49. iXBRLViewerPlugin/viewer/src/i18n/es/scale.json +16 -0
  50. iXBRLViewerPlugin/viewer/src/i18n/es/tooltips.json +17 -0
  51. iXBRLViewerPlugin/viewer/src/i18n/es/translation.json +87 -37
  52. iXBRLViewerPlugin/viewer/src/i18n/fr/balancetypes.json +4 -0
  53. iXBRLViewerPlugin/viewer/src/i18n/fr/currencies.json +13 -0
  54. iXBRLViewerPlugin/viewer/src/i18n/fr/datatypes.json +9 -0
  55. iXBRLViewerPlugin/viewer/src/i18n/fr/labelroles.json +24 -0
  56. iXBRLViewerPlugin/viewer/src/i18n/fr/referenceparts.json +10 -0
  57. iXBRLViewerPlugin/viewer/src/i18n/fr/scale.json +15 -0
  58. iXBRLViewerPlugin/viewer/src/i18n/fr/tooltips.json +17 -0
  59. iXBRLViewerPlugin/viewer/src/i18n/fr/translation.json +179 -0
  60. iXBRLViewerPlugin/viewer/src/i18n/nl/balancetypes.json +4 -0
  61. iXBRLViewerPlugin/viewer/src/i18n/nl/currencies.json +13 -0
  62. iXBRLViewerPlugin/viewer/src/i18n/nl/datatypes.json +9 -0
  63. iXBRLViewerPlugin/viewer/src/i18n/nl/labelroles.json +24 -0
  64. iXBRLViewerPlugin/viewer/src/i18n/nl/referenceparts.json +10 -0
  65. iXBRLViewerPlugin/viewer/src/i18n/nl/scale.json +15 -0
  66. iXBRLViewerPlugin/viewer/src/i18n/nl/tooltips.json +17 -0
  67. iXBRLViewerPlugin/viewer/src/i18n/nl/translation.json +179 -0
  68. iXBRLViewerPlugin/viewer/src/i18n/uk/balancetypes.json +4 -0
  69. iXBRLViewerPlugin/viewer/src/i18n/uk/currencies.json +13 -0
  70. iXBRLViewerPlugin/viewer/src/i18n/uk/datatypes.json +9 -0
  71. iXBRLViewerPlugin/viewer/src/i18n/uk/labelroles.json +24 -0
  72. iXBRLViewerPlugin/viewer/src/i18n/uk/referenceparts.json +10 -0
  73. iXBRLViewerPlugin/viewer/src/i18n/uk/scale.json +15 -0
  74. iXBRLViewerPlugin/viewer/src/i18n/uk/tooltips.json +17 -0
  75. iXBRLViewerPlugin/viewer/src/i18n/uk/translation.json +179 -0
  76. iXBRLViewerPlugin/viewer/src/icons/calculator.svg +13 -0
  77. iXBRLViewerPlugin/viewer/src/icons/circle-cross.svg +11 -0
  78. iXBRLViewerPlugin/viewer/src/icons/circle-tick.svg +11 -0
  79. iXBRLViewerPlugin/viewer/src/icons/dark-mode.svg +4 -0
  80. iXBRLViewerPlugin/viewer/src/icons/dimension.svg +1 -5
  81. iXBRLViewerPlugin/viewer/src/icons/member.svg +2 -5
  82. iXBRLViewerPlugin/viewer/src/icons/multi-tag.svg +10 -0
  83. iXBRLViewerPlugin/viewer/src/img/arelle-dark.svg +179 -0
  84. iXBRLViewerPlugin/viewer/src/img/inline-viewer-dark.svg +59 -0
  85. iXBRLViewerPlugin/viewer/src/js/accordian.js +5 -4
  86. iXBRLViewerPlugin/viewer/src/js/aspect.js +29 -10
  87. iXBRLViewerPlugin/viewer/src/js/aspect.test.js +40 -31
  88. iXBRLViewerPlugin/viewer/src/js/balance.js +14 -0
  89. iXBRLViewerPlugin/viewer/src/js/calculation.js +213 -0
  90. iXBRLViewerPlugin/viewer/src/js/calculation.test.js +306 -0
  91. iXBRLViewerPlugin/viewer/src/js/calculationInspector.js +187 -0
  92. iXBRLViewerPlugin/viewer/src/js/chart.js +26 -24
  93. iXBRLViewerPlugin/viewer/src/js/chart.test.js +10 -9
  94. iXBRLViewerPlugin/viewer/src/js/concept.js +37 -4
  95. iXBRLViewerPlugin/viewer/src/js/concept.test.js +30 -6
  96. iXBRLViewerPlugin/viewer/src/js/datatype.js +20 -0
  97. iXBRLViewerPlugin/viewer/src/js/datatype.test.js +62 -0
  98. iXBRLViewerPlugin/viewer/src/js/dialog.js +6 -4
  99. iXBRLViewerPlugin/viewer/src/js/docOrderIndex.js +7 -7
  100. iXBRLViewerPlugin/viewer/src/js/fact.js +156 -59
  101. iXBRLViewerPlugin/viewer/src/js/fact.test.js +160 -29
  102. iXBRLViewerPlugin/viewer/src/js/factset.js +64 -15
  103. iXBRLViewerPlugin/viewer/src/js/factset.test.js +102 -31
  104. iXBRLViewerPlugin/viewer/src/js/footnote.js +8 -2
  105. iXBRLViewerPlugin/viewer/src/js/index.js +11 -3
  106. iXBRLViewerPlugin/viewer/src/js/inspector.js +747 -221
  107. iXBRLViewerPlugin/viewer/src/js/inspector.test.js +143 -25
  108. iXBRLViewerPlugin/viewer/src/js/interval.js +70 -0
  109. iXBRLViewerPlugin/viewer/src/js/interval.test.js +153 -0
  110. iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js +391 -262
  111. iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.test.js +134 -20
  112. iXBRLViewerPlugin/viewer/src/js/ixnode.js +1 -1
  113. iXBRLViewerPlugin/viewer/src/js/menu.js +25 -7
  114. iXBRLViewerPlugin/viewer/src/js/number-matcher.js +7 -3
  115. iXBRLViewerPlugin/viewer/src/js/number-matcher.test.js +4 -0
  116. iXBRLViewerPlugin/viewer/src/js/outline.js +34 -13
  117. iXBRLViewerPlugin/viewer/src/js/outline.test.js +97 -91
  118. iXBRLViewerPlugin/viewer/src/js/period.js +0 -1
  119. iXBRLViewerPlugin/viewer/src/js/report.js +260 -351
  120. iXBRLViewerPlugin/viewer/src/js/report.test.js +95 -27
  121. iXBRLViewerPlugin/viewer/src/js/reportset.js +264 -0
  122. iXBRLViewerPlugin/viewer/src/js/reportset.test.js +357 -0
  123. iXBRLViewerPlugin/viewer/src/js/search.js +72 -38
  124. iXBRLViewerPlugin/viewer/src/js/search.test.js +184 -84
  125. iXBRLViewerPlugin/viewer/src/js/summary.js +34 -8
  126. iXBRLViewerPlugin/viewer/src/js/summary.test.js +69 -25
  127. iXBRLViewerPlugin/viewer/src/js/tableExport.js +9 -9
  128. iXBRLViewerPlugin/viewer/src/js/taxonomynamer.js +34 -0
  129. iXBRLViewerPlugin/viewer/src/js/taxonomynamer.test.js +32 -0
  130. iXBRLViewerPlugin/viewer/src/js/test-utils.js +46 -0
  131. iXBRLViewerPlugin/viewer/src/js/theme.js +50 -0
  132. iXBRLViewerPlugin/viewer/src/js/unit.js +90 -32
  133. iXBRLViewerPlugin/viewer/src/js/unit.test.js +62 -25
  134. iXBRLViewerPlugin/viewer/src/js/util.js +94 -0
  135. iXBRLViewerPlugin/viewer/src/js/util.test.js +33 -1
  136. iXBRLViewerPlugin/viewer/src/js/utr.js +27 -0
  137. iXBRLViewerPlugin/viewer/src/js/viewer.js +205 -181
  138. iXBRLViewerPlugin/viewer/src/js/viewerOptions.js +0 -2
  139. iXBRLViewerPlugin/viewer/src/less/accordian.less +10 -6
  140. iXBRLViewerPlugin/viewer/src/less/block-list.less +16 -5
  141. iXBRLViewerPlugin/viewer/src/less/calculation-inspector.less +83 -0
  142. iXBRLViewerPlugin/viewer/src/less/chart.less +8 -5
  143. iXBRLViewerPlugin/viewer/src/less/colours-dark-mode.less +40 -0
  144. iXBRLViewerPlugin/viewer/src/less/colours.less +32 -20
  145. iXBRLViewerPlugin/viewer/src/less/common.less +3 -3
  146. iXBRLViewerPlugin/viewer/src/less/components.less +6 -4
  147. iXBRLViewerPlugin/viewer/src/less/core.less +2 -0
  148. iXBRLViewerPlugin/viewer/src/less/dialog.less +21 -14
  149. iXBRLViewerPlugin/viewer/src/less/form-controls.less +33 -11
  150. iXBRLViewerPlugin/viewer/src/less/inspector.less +1045 -726
  151. iXBRLViewerPlugin/viewer/src/less/loader.less +2 -2
  152. iXBRLViewerPlugin/viewer/src/less/menu.less +33 -15
  153. iXBRLViewerPlugin/viewer/src/less/summary.less +16 -6
  154. iXBRLViewerPlugin/viewer/src/less/tabs.less +9 -9
  155. iXBRLViewerPlugin/viewer/src/less/text-block-viewer.less +2 -0
  156. iXBRLViewerPlugin/viewer/src/less/text-mixins.less +2 -1
  157. iXBRLViewerPlugin/viewer/src/less/validation-report.less +2 -3
  158. iXBRLViewerPlugin/viewer/src/less/viewer.less +105 -74
  159. iXBRLViewerPlugin/viewer/webpack.common.js +19 -9
  160. iXBRLViewerPlugin/xhtmlserialize.py +59 -45
  161. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/METADATA +181 -50
  162. ixbrl_viewer-1.4.86.dist-info/RECORD +217 -0
  163. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/WHEEL +1 -1
  164. ixbrl_viewer-1.4.1.dist-info/LICENSE → ixbrl_viewer-1.4.86.dist-info/licenses/LICENSE.md +8 -14
  165. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/top_level.txt +0 -1
  166. iXBRLViewerPlugin/viewer/src/js/calculations.js +0 -111
  167. iXBRLViewerPlugin/viewer/src/js/interact.min.js +0 -6
  168. ixbrl_viewer-1.4.1.dist-info/RECORD +0 -155
  169. tests/__init__.py +0 -0
  170. tests/puppeteer/framework/core_elements.js +0 -117
  171. tests/puppeteer/framework/page_objects/doc_frame.js +0 -105
  172. tests/puppeteer/framework/page_objects/fact_details_panel.js +0 -80
  173. tests/puppeteer/framework/page_objects/search_panel.js +0 -76
  174. tests/puppeteer/framework/page_objects/toolbar.js +0 -18
  175. tests/puppeteer/framework/utils.js +0 -3
  176. tests/puppeteer/framework/viewer_page.js +0 -103
  177. tests/puppeteer/puppeteer_test_run_via_intellij.jpg +0 -0
  178. tests/puppeteer/test_filings/filing_documents_smoke_test.zip +0 -0
  179. tests/puppeteer/test_filings/highlights.zip +0 -0
  180. tests/puppeteer/tests/fact_properties.test.js +0 -78
  181. tests/puppeteer/tests/highlight.test.js +0 -186
  182. tests/puppeteer/tests/search.test.js +0 -86
  183. tests/puppeteer/tools/generate.sh +0 -15
  184. tests/unit_tests/__init__.py +0 -0
  185. tests/unit_tests/iXBRLViewerPlugin/__init__.py +0 -0
  186. tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py +0 -39
  187. tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py +0 -641
  188. tests/unit_tests/iXBRLViewerPlugin/test_xhtmlserialize.py +0 -310
  189. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/entry_points.txt +0 -0
  190. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info/licenses}/NOTICE +0 -0
@@ -1,8 +1,12 @@
1
1
  # See COPYRIGHT.md for copyright information
2
2
 
3
- from lxml import etree
4
- from enum import Enum
3
+ from __future__ import annotations
4
+
5
5
  import re
6
+ from enum import Enum
7
+ from typing import IO
8
+
9
+ from lxml import etree
6
10
 
7
11
  XHTML_NS = 'http://www.w3.org/1999/xhtml'
8
12
  XML_NS = 'http://www.w3.org/XML/1998/namespace'
@@ -34,31 +38,31 @@ class XHTMLSerializer:
34
38
  ATTR_ESCAPE_RE = re.compile('([' + MUST_ESCAPE_CHARS + '>"])')
35
39
  STYLE_ESCAPE_RE = re.compile('([' + MUST_ESCAPE_CHARS + ']|' + CDATA_END + ')')
36
40
 
37
- def __init__(self, fout, xml_declaration = True, assume_xhtml = True):
41
+ def __init__(self, fout: IO[bytes], xml_declaration: bool = True, assume_xhtml: bool = True) -> None:
38
42
  self.fout = fout
39
43
  self.encoding = "utf-8"
40
44
  self.xml_declaration = xml_declaration
41
45
  self.assume_xhtml = assume_xhtml
42
46
 
43
- def write(self, s):
47
+ def write(self, s: str) -> None:
44
48
  self.fout.write(s.encode(self.encoding))
45
49
 
46
- def prefix_sort(self, p):
50
+ def prefix_sort(self, p: str | None) -> str:
47
51
  return p if p is not None else '0'
48
52
 
49
- def qname_for_node(self, node):
50
- qname = etree.QName(node.tag)
53
+ def qname_for_node(self, node: etree._Element) -> str:
54
+ qname = etree.QName(node)
51
55
  if qname.namespace is None:
52
56
  prefix = None
53
57
  elif node.nsmap.get(node.prefix, None) == qname.namespace:
54
58
  prefix = node.prefix
55
59
  else:
56
- prefix = next(iter(sorted((p for p, ns in nsmap.items() if ns == qname.namespace), key = self.prefix_sort)))
60
+ prefix = next(iter(sorted((p for p, ns in node.nsmap.items() if ns == qname.namespace), key = self.prefix_sort)))
57
61
  if prefix is None:
58
62
  return qname.localname
59
- return "%s:%s" % (prefix, qname.localname)
63
+ return f"{prefix}:{qname.localname}"
60
64
 
61
- def qname_for_attr(self, tag, nsmap):
65
+ def qname_for_attr(self, tag: etree._Element | str, nsmap: dict[str | None, str]) -> str:
62
66
  qname = etree.QName(tag)
63
67
  if qname.namespace is None:
64
68
  return qname.localname
@@ -66,9 +70,9 @@ class XHTMLSerializer:
66
70
  prefix = 'xml'
67
71
  else:
68
72
  prefix = next(iter(sorted((p for p, ns in nsmap.items() if ns == qname.namespace and p is not None), key = self.prefix_sort)))
69
- return "%s:%s" % (prefix, qname.localname)
73
+ return f"{prefix}:{qname.localname}"
70
74
 
71
- def is_selfclosable(self, n):
75
+ def is_selfclosable(self, n: etree._Element | str) -> bool:
72
76
  qname = etree.QName(n)
73
77
  return (
74
78
  qname.localname in XHTMLSerializer.SELF_CLOSABLE
@@ -76,22 +80,22 @@ class XHTMLSerializer:
76
80
  qname.namespace == XHTML_NS
77
81
  or (self.assume_xhtml and qname.namespace is None)))
78
82
 
79
- def escape_attr(self, s):
83
+ def escape_attr(self, s: str) -> str:
80
84
  return self.ATTR_ESCAPE_RE.sub(lambda m: self.escape_str(m[0]), s)
81
85
 
82
- def xmlns_declaration(self, prefix, uri):
86
+ def xmlns_declaration(self, prefix: str | None, uri: str) -> str:
83
87
  if prefix is None:
84
- return 'xmlns="%s"' % self.escape_attr(uri)
85
- return 'xmlns:%s="%s"' % (prefix, self.escape_attr(uri))
88
+ return f'xmlns="{self.escape_attr(uri)}"'
89
+ return f'xmlns:{prefix}="{self.escape_attr(uri)}"'
86
90
 
87
- def namespace_declarations(self, new_nsmap, cur_nsmap):
91
+ def namespace_declarations(self, new_nsmap: dict[str | None, str], cur_nsmap: dict[str | None, str]) -> list[str]:
88
92
  changed = set(p[0] for p in (set(new_nsmap.items()) ^ set(cur_nsmap.items())))
89
93
  return sorted(self.xmlns_declaration(p, new_nsmap[p]) for p in changed)
90
94
 
91
- def escape_str(self, c):
92
- return self.ESCAPES.get(c, '&#x%02X;' % ord(c[0]))
95
+ def escape_str(self, c: str) -> str:
96
+ return self.ESCAPES.get(c, f'&#x{ord(c[0]):02X};')
93
97
 
94
- def write_escape_text(self, s, escape_mode):
98
+ def write_escape_text(self, s: str | None, escape_mode: EscapeMode) -> None:
95
99
  if s is None:
96
100
  return
97
101
  if escape_mode == EscapeMode.STYLE:
@@ -105,24 +109,31 @@ class XHTMLSerializer:
105
109
  else:
106
110
  self.write(self.ESCAPE_RE.sub(lambda m: self.escape_str(m[0]),s))
107
111
 
108
- def write_attributes(self, node):
112
+ def write_attributes(self, node: etree._Element) -> None:
109
113
  for qname, value in sorted((self.qname_for_attr(k, node.nsmap), v) for k, v in node.items()):
110
- self.write(' %s="' % qname)
114
+ self.write(f' {qname}="')
111
115
  self.write(self.escape_attr(value))
112
116
  self.write("\"")
113
117
 
114
- def write_comment(self, n, escape_mode):
118
+ def write_comment(self, n: etree._Comment, escape_mode: EscapeMode) -> None:
115
119
  self.write('<!--' + n.text + '-->')
116
120
  self.write_escape_text(n.tail, escape_mode)
117
121
 
118
- def write_processing_instruction(self, n, escape_mode):
122
+ def write_processing_instruction(self, n: etree._ProcessingInstruction, escape_mode: EscapeMode) -> None:
119
123
  self.write( '<?' + n.target )
120
124
  if n.text != '':
121
125
  self.write(' ' + n.text)
122
126
  self.write('?>')
123
127
  self.write_escape_text(n.tail, escape_mode)
124
128
 
125
- def write_node(self, n, nsmap = {}, escape_mode = EscapeMode.DEFAULT):
129
+ def write_node(
130
+ self,
131
+ n: etree._Element,
132
+ nsmap: dict[str | None, str] | None = None,
133
+ escape_mode: EscapeMode = EscapeMode.DEFAULT,
134
+ ) -> None:
135
+ if nsmap is None:
136
+ nsmap = {}
126
137
  if isinstance(n, etree._Comment):
127
138
  self.write_comment(n, escape_mode)
128
139
  elif isinstance(n, etree._ProcessingInstruction):
@@ -130,18 +141,22 @@ class XHTMLSerializer:
130
141
  else:
131
142
  self.write_element(n, nsmap, escape_mode)
132
143
 
133
- def write_element(self, n, parent_nsmap = {}, escape_mode = EscapeMode.DEFAULT):
144
+ def write_element(
145
+ self,
146
+ n: etree._Element,
147
+ parent_nsmap: dict[str | None, str] | None = None,
148
+ escape_mode: EscapeMode = EscapeMode.DEFAULT,
149
+ ) -> None:
150
+ if parent_nsmap is None:
151
+ parent_nsmap = {}
134
152
  name = self.qname_for_node(n)
135
- qname = etree.QName(n.tag)
153
+ qname = etree.QName(n)
136
154
  selfclose = len(n) == 0 and n.text is None and self.is_selfclosable(n)
137
- parts = [ name ] + self.namespace_declarations(n.nsmap, parent_nsmap)
155
+ parts = [ name ] + self.namespace_declarations(n.nsmap, parent_nsmap)
138
156
  self.write('<' + ' '.join(parts))
139
157
  self.write_attributes(n)
140
158
 
141
- if qname.localname == 'style':
142
- inner_escape_mode = EscapeMode.STYLE
143
- else:
144
- inner_escape_mode = escape_mode
159
+ inner_escape_mode = EscapeMode.STYLE if qname.localname == 'style' else escape_mode
145
160
 
146
161
  if selfclose:
147
162
  self.write('/>')
@@ -150,11 +165,11 @@ class XHTMLSerializer:
150
165
  self.write_escape_text(n.text, inner_escape_mode)
151
166
  for child in n.iterchildren():
152
167
  self.write_node(child, n.nsmap, inner_escape_mode)
153
- self.write('</%s>' % name)
168
+ self.write(f'</{name}>')
154
169
 
155
170
  self.write_escape_text(n.tail, escape_mode)
156
171
 
157
- def write_xml_declaration(self, docinfo = None):
172
+ def write_xml_declaration(self, docinfo: etree.DocInfo | None = None) -> None:
158
173
  if self.xml_declaration:
159
174
  version = "1.0"
160
175
  standalone = ""
@@ -162,23 +177,22 @@ class XHTMLSerializer:
162
177
  version = docinfo.xml_version
163
178
  if docinfo.standalone:
164
179
  standalone = ' standalone="yes"'
165
- self.write('<?xml version="%s" encoding="%s"%s?>\n' % (version, self.encoding, standalone))
180
+ self.write(f'<?xml version="{version}" encoding="{self.encoding}"{standalone}?>\n')
166
181
 
167
- def serialize(self, element):
168
- if hasattr(element, 'getroot'):
182
+ def serialize(self, element: etree._ElementTree[etree._Element] | etree._Element) -> None:
183
+ if isinstance(element, etree._ElementTree):
169
184
  self.write_xml_declaration(element.docinfo)
170
185
 
171
- element = element.getroot()
172
- while element.getprevious() is not None:
173
- element = element.getprevious()
186
+ node: etree._Element | None = element.getroot()
187
+ while node is not None and node.getprevious() is not None:
188
+ node = node.getprevious()
174
189
 
175
- while element is not None:
176
- self.write_node(element)
177
- if isinstance(element, (etree._Comment, etree._ProcessingInstruction)):
190
+ while node is not None:
191
+ self.write_node(node)
192
+ if isinstance(node, (etree._Comment, etree._ProcessingInstruction)):
178
193
  self.write("\n")
179
- element = element.getnext()
194
+ node = node.getnext()
180
195
 
181
196
  else:
182
197
  self.write_xml_declaration()
183
198
  self.write_element(element)
184
-
@@ -1,9 +1,9 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: ixbrl-viewer
3
- Version: 1.4.1
3
+ Version: 1.4.86
4
4
  Summary: The Arelle iXBRL Viewer allows iXBRL reports to be viewed interactively in a web browser.
5
5
  Author-email: "arelle.org" <support@arelle.org>
6
- License: Apache-2.0
6
+ License-Expression: Apache-2.0
7
7
  Project-URL: Homepage, https://arelle.org/
8
8
  Project-URL: Downloads, https://arelle.org/arelle/pub/
9
9
  Project-URL: Documentation, https://arelle.org/arelle/documentation/
@@ -16,64 +16,115 @@ Platform: any
16
16
  Classifier: Development Status :: 5 - Production/Stable
17
17
  Classifier: Intended Audience :: End Users/Desktop
18
18
  Classifier: Intended Audience :: Developers
19
- Classifier: License :: OSI Approved :: Apache Software License
20
19
  Classifier: Natural Language :: English
21
20
  Classifier: Programming Language :: Python :: 3
22
- Classifier: Programming Language :: Python :: 3.8
23
- Classifier: Programming Language :: Python :: 3.9
24
21
  Classifier: Programming Language :: Python :: 3.10
25
22
  Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
26
26
  Classifier: Operating System :: OS Independent
27
27
  Classifier: Topic :: Text Processing :: Markup :: XML
28
- Requires-Python: >=3.8
28
+ Requires-Python: >=3.10
29
29
  Description-Content-Type: text/markdown
30
- License-File: LICENSE
30
+ License-File: LICENSE.md
31
31
  License-File: NOTICE
32
- Requires-Dist: arelle-release ==2.*
33
- Requires-Dist: lxml ==4.*
34
- Requires-Dist: pycountry ==22.*
32
+ Requires-Dist: bottle<0.14,>=0.13
33
+ Requires-Dist: lxml<7,>=4
34
+ Provides-Extra: arelle
35
+ Requires-Dist: arelle_release==2.*; extra == "arelle"
35
36
  Provides-Extra: dev
36
- Requires-Dist: nose2 ==0.13.0 ; extra == 'dev'
37
- Requires-Dist: typing-extensions ==4.7.1 ; extra == 'dev'
37
+ Requires-Dist: flake8==7.3.0; extra == "dev"
38
+ Requires-Dist: mypy==1.19.1; extra == "dev"
39
+ Requires-Dist: pytest==9.0.2; extra == "dev"
40
+ Requires-Dist: types-lxml==2026.1.1; extra == "dev"
41
+ Requires-Dist: typing-extensions==4.15.0; extra == "dev"
42
+ Dynamic: license-file
38
43
 
39
44
  # Arelle iXBRL Viewer
40
45
 
46
+ [![PyPI](https://img.shields.io/pypi/v/ixbrl-viewer)](https://pypi.org/project/ixbrl-viewer/)
47
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ixbrl-viewer)](https://pypi.org/project/ixbrl-viewer/)
48
+ [![NPM Version](https://img.shields.io/npm/v/ixbrl-viewer)](https://www.npmjs.com/package/ixbrl-viewer)
49
+ [![Read the Docs](https://img.shields.io/readthedocs/arelle-ixbrl-viewer)](https://arelle-ixbrl-viewer.readthedocs.io/)
50
+
41
51
  ![ixbrl-viewer](https://raw.githubusercontent.com/Arelle/ixbrl-viewer/master/examples/ixbrl-viewer-demo.gif)
42
52
 
53
+ ## Table of Contents
54
+
55
+ - [Arelle iXBRL Viewer](#arelle-ixbrl-viewer)
56
+ - [Table of Contents](#table-of-contents)
57
+ - [Description](#description)
58
+ - [Documentation](#documentation)
59
+ - [Installation](#installation)
60
+ - [Accessing the JavaScript viewer application](#accessing-the-javascript-viewer-application)
61
+ - [Accessing via the CDN](#accessing-via-the-cdn)
62
+ - [Accessing via Github](#accessing-via-github)
63
+ - [Building the JavaScript locally](#building-the-javascript-locally)
64
+ - [JavaScript Versioning](#javascript-versioning)
65
+ - [Producing an ixbrl-viewer via the Arelle GUI](#producing-an-ixbrl-viewer-via-the-arelle-gui)
66
+ - [Preparing an iXBRL file via the GUI](#preparing-an-ixbrl-file-via-the-gui)
67
+ - [Preparing an iXBRL document set using the Arelle GUI](#preparing-an-ixbrl-document-set-using-the-arelle-gui)
68
+ - [Producing an ixbrl-viewer via the Arelle command line](#producing-an-ixbrl-viewer-via-the-arelle-command-line)
69
+ - [Preparing an iXBRL file via the command line](#preparing-an-ixbrl-file-via-the-command-line)
70
+ - [Preparing an iXBRL document set](#preparing-an-ixbrl-document-set)
71
+ - [Using build-viewer.py](#using-build-viewerpy)
72
+ - [Stub viewer mode](#stub-viewer-mode)
73
+ - [Optional Features](#optional-features)
74
+ - [Feature: Review Mode](#feature-review-mode)
75
+ - [Runtime config](#runtime-config)
76
+ - [Disable viewer loading](#disable-viewer-loading)
77
+ - [Running tests](#running-tests)
78
+ - [Running unit tests](#running-unit-tests)
79
+ - [Running Puppeteer tests](#running-puppeteer-tests)
80
+ - [👥 Contributors](#-contributors)
81
+ - [License](#license)
82
+
83
+ ## Description
84
+
43
85
  The [Arelle](https://arelle.org/) iXBRL Viewer allows [Inline XBRL](https://www.xbrl.org/ixbrl) (or iXBRL) reports to be
44
86
  viewed interactively in a web browser. The viewer allows users to access the tagged XBRL data embedded in an iXBRL
45
87
  report. Key features include:
46
88
 
47
- * Full text search on taxonomy labels and references
48
- * View full details of tagged facts
49
- * Export tables to Excel
50
- * Visualize and navigate calculation relationships
51
- * Produce on-the-fly graphs using XBRL data
89
+ - Full text search on taxonomy labels and references
90
+ - View full details of tagged facts
91
+ - Export tables to Excel
92
+ - Visualize and navigate calculation relationships
93
+ - Produce on-the-fly graphs using XBRL data
52
94
 
53
95
  A sample viewer is provided in the [examples](https://github.com/Arelle/ixbrl-viewer/blob/master/examples/README.md) for those interested.
54
96
 
55
97
  The viewer project consists of two components:
56
98
 
57
- * A plugin for the [Arelle](https://www.arelle.org) XBRL tool
58
- * The Javascript viewer application
99
+ - A plugin for the [Arelle](https://www.arelle.org) XBRL tool
100
+ - The Javascript viewer application
59
101
 
60
102
  In order to view an iXBRL report in the viewer, it must first be prepared using
61
103
  the Arelle plugin. The preparation process updates the iXBRL file to include:
62
104
 
63
- 1. A link to the Javascript viewer
105
+ 1. A link to the JavaScript viewer
64
106
  2. A block of JSON data that contains the results of processing the XBRL data and associated taxonomy
65
107
 
66
- Once prepared, the resulting file provides an entirely standalone viewer. Once
67
- prepared, the viewer is entirely standalone, and does not require access to the
68
- taxonomy, or to any online services. The only dependency is on the javascript
69
- viewer application, which is a single file which can be accessed directly online, downloaded or built locally.
108
+ Once prepared, the resulting file provides an entirely standalone viewer, and
109
+ does not require access to the taxonomy, or to any online services. The only
110
+ dependency is on the JavaScript viewer application, which is a single file
111
+ which can be accessed directly online, downloaded or built locally.
112
+
113
+ It is also possible to place the link to the viewer, and the block of JSON data
114
+ in a separate file. See Stub Viewer Mode below.
115
+
116
+ The JavaScript viewer application is a single JavaScript file called ixbrlviewer.js. It
117
+ contains all of the JavaScript that runs the viewer functionality.
70
118
 
71
- The javascript viewer application is a single Javascript file called ixbrlviewer.js. It
72
- contains all of the javascript that runs the viewer functionality.
119
+ ## Documentation
120
+
121
+ Need help with the Arelle iXBRL Viewer? Go check out [our documentation][read-the-docs].
122
+
123
+ [read-the-docs]: https://arelle-ixbrl-viewer.readthedocs.io/
73
124
 
74
125
  ## Installation
75
126
 
76
- The python portion of this repo is developed using Python 3.11.
127
+ The Python portion of this repo is developed using Python 3.14.
77
128
 
78
129
  1. Clone the [iXBRL Viewer git repository][ixbrlviewer-github].
79
130
  2. Download and install [Arelle][arelle-download]
@@ -113,11 +164,15 @@ the ixbrl-viewer.
113
164
 
114
165
  ## JavaScript Versioning
115
166
 
116
- The ixbrl-viewer plugin embeds processed XBRL metadata in the HTML that has a specific format read
117
- by the JavaScript. The metadata produced by a version will be broken if a major version bump is
118
- released. The new javascript won't necessarily work with older versions of the generated metadata.
119
- if a minor version bump is released, then the metadata format was updated, any ixbrl-viewer produced
120
- on that minor version will have to use at least that minor version for the javascript.
167
+ The ixbrl-viewer plugin embeds processed XBRL metadata in the HTML that has a
168
+ specific format read by the JavaScript. The metadata produced will work with a
169
+ viewer application that has the same major version, and the same or later minor
170
+ version as the plugin used to create it.
171
+
172
+ This means that once an XBRL report has been prepared by the plugin, the
173
+ associated JavaScript viewer application can be upgraded within the same major
174
+ version. Any features introduced in newer versions of the viewer that rely on
175
+ additional metadata will degrade gracefully if that metadata is not present.
121
176
 
122
177
  ## Producing an ixbrl-viewer via the Arelle GUI
123
178
 
@@ -163,9 +218,9 @@ python3 Arelle/arelleCmdLine.py --plugins=<path to iXBRLViewerPlugin> -f ixbrl-r
163
218
 
164
219
  Notes:
165
220
 
166
- * "Arelle/arelleCmdLine.py" should be the path to your installation of Arelle
167
- * The plugin path needs to an absolute file path to the ixbrl-viewer plugin
168
- * The viewer url can be one of the following:
221
+ - "Arelle/arelleCmdLine.py" should be the path to your installation of Arelle
222
+ - The plugin path needs to an absolute file path to the ixbrl-viewer plugin
223
+ - The viewer url can be one of the following:
169
224
 
170
225
  1. `https://cdn.jsdelivr.net/npm/ixbrl-viewer@<version>/iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js`
171
226
  2. A relative url to the downloaded ixviewer.js from github
@@ -195,17 +250,20 @@ python3 Arelle/arelleCmdLine.py --plugins '/path/to/iXBRLViewerPlugin|inlineXbrl
195
250
 
196
251
  Notes:
197
252
 
198
- * The first file specified is the "primary" file, and should be opened in a
253
+ - The first file specified is the "primary" file, and should be opened in a
199
254
  browser to use the viewer. The other files will be loaded in separate tabs
200
255
  within the viewer.
201
- * "Arelle/arelleCmdLine.py" should be the path to your installation of Arelle
202
- * The plugin path needs to an absolute file path to the ixbrl-viewer plugin
203
- * The viewer url can be one of the following:
256
+ - "Arelle/arelleCmdLine.py" should be the path to your installation of Arelle
257
+ - The plugin path needs to an absolute file path to the ixbrl-viewer plugin
258
+ - The viewer url can be one of the following:
204
259
 
205
260
  1. `https://cdn.jsdelivr.net/npm/ixbrl-viewer@<version>/iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js`
206
261
  2. A relative url to the downloaded ixviewer.js from github
207
262
  3. A relative url to the locally built ixviewer.js
208
263
 
264
+ - Due to browser security restrictions, the resulting viewer cannot be loaded
265
+ directly from `file:` URLs; it must be served by a web server.
266
+
209
267
  ### Using build-viewer.py
210
268
 
211
269
  As an alternative to the standard Arelle command line, the
@@ -229,10 +287,33 @@ e.g.
229
287
  ```shell
230
288
  PYTHONPATH=/path/to/Arelle:/path/to/ixbrl-viewer ./samples/build-viewer.py --out out-dir --package-dir /my/packages/ ixds-dir
231
289
  ```
232
- # Optional Features
290
+
291
+ ## Stub viewer mode
292
+
293
+ By default, the link to the JavaScript viewer and the JSON data block are added
294
+ to the iXBRL report file (or to the first file, in the case of a document set).
295
+
296
+ Stub viewer mode is an optional generation mode that creates an additional,
297
+ minimal HTML file containing the JSON data block, and the link to the
298
+ JavaScript viewer. This mode has two advantages over the default approach of
299
+ embedding the JSON data and JavaScript link in the iXBRL report:
300
+
301
+ 1. Provided that all facts and footnotes in the iXBRL report already have ID
302
+ attributes, no modification of the iXBRL report is required.
303
+ 2. The iXBRL viewer loading mask will be displayed much more quickly. This is
304
+ helpful for very large iXBRL reports which can otherwise result in a long
305
+ delay before there is any sign of the iXBRL Viewer loading.
306
+
307
+ The downside of this mode is that due to browser security restrictions, the
308
+ viewer cannot be loaded directly from files (using `file:` URLs); they must be
309
+ served by a web server.
310
+
311
+ ## Optional Features
312
+
233
313
  Some features are disabled by default but can be enabled at generation time or with query parameters.
234
314
 
235
315
  To enable features:
316
+
236
317
  - Via CLI: `--viewer-feature-{feature name}`
237
318
  - Via query parameter:`?{feature name}=true`
238
319
 
@@ -251,7 +332,8 @@ This table uses the 'review' feature as an example to demonstrate how these opti
251
332
  | `review` | `true` | `enabled` |
252
333
  | `review` | `false` | `disabled` |
253
334
 
254
- ## Feature: Review Mode
335
+ ### Feature: Review Mode
336
+
255
337
  ![ixbrl-viewer](https://raw.githubusercontent.com/Arelle/ixbrl-viewer/master/examples/review-mode.png)
256
338
 
257
339
  A review mode is available that is intended to assist in reviewing partially tagged or incomplete documents.
@@ -261,6 +343,40 @@ This mode replaces the namespace-based highlighting with optional highlighting b
261
343
  |---------------------------|----------------|
262
344
  | `--viewer-feature-review` | `?review=true` |
263
345
 
346
+ ## Runtime config
347
+
348
+ When launched, the viewer will check for the existence of
349
+ `ixbrlviewer.config.json` in the same directory as `ixbrlviewer.js`. If found,
350
+ this will be loaded and used to configure the viewer.
351
+
352
+ The file supports the following keys:
353
+
354
+ - `features` - a JSON object containing defaults for features. These will be
355
+ overridden by features defined at generation time, and then by query
356
+ parameters, as defined above.
357
+
358
+ - `skin` - a JSON object supporting the following keys:
359
+
360
+ - `stylesheetUrl` - a URL to additional CSS definitions.
361
+ - `faviconUrl` - a URL to an icon file to be used as the favicon for the viewer.
362
+ - `footerLogoHtml` - a fragment of HTML that will be included in place of the standard footer logo.
363
+
364
+ - `taxonomyNames` - a JSON object where:
365
+
366
+ - Keys are strings that will be treated as a regular expression to match
367
+ against a namespace.
368
+ - Values are an array of (prefix, name) where "prefix" is the preferred
369
+ namespace prefix for the namespace, and "name" is a short descriptive
370
+ name for the taxonomy.
371
+
372
+ Relative URLs defined in the config file are resolved relative to the config file.
373
+
374
+ ## Disable viewer loading
375
+
376
+ Loading of the viewer can be disabled by specifying `?disable-viewer` as a
377
+ query parameter. This will leave the iXBRL document loaded in the browser, but
378
+ without any viewer functionality. In the case of an iXBRL document set, or
379
+ multi-document viewer, the first document will be shown.
264
380
 
265
381
  ## Running tests
266
382
 
@@ -272,7 +388,7 @@ Run the following command to run javascript unit tests: `npm run test`
272
388
 
273
389
  In order to run the python unit tests make sure that you have pip installed requirements-dev.txt.
274
390
 
275
- Run the following command to run python unit tests: `nose2`
391
+ Run the following command to run python unit tests: `pytest tests/unit_tests`
276
392
 
277
393
  ### Running Puppeteer tests
278
394
 
@@ -282,7 +398,7 @@ All commands should be run from repository root
282
398
  2. Install Arelle
283
399
 
284
400
  ```shell
285
- pip install arelle-release .
401
+ pip install .[arelle]
286
402
  ```
287
403
 
288
404
  3. [Terminal 1] Start the puppeteer serve
@@ -291,16 +407,31 @@ All commands should be run from repository root
291
407
  npm run puppeteerServe
292
408
  ```
293
409
 
294
- * This command generates the `ixbrlviewer.js`, uses Arelle to generate several test files, then serves the files via a nodejs http-server.
295
- * Currently changes to application code require restarting this step to take effect.
410
+ - This command generates the `ixbrlviewer.js`, uses Arelle to generate several test files, then serves the files via a nodejs http-server.
411
+ - Currently changes to application code require restarting this step to take effect.
296
412
  4. Start the puppeteer tests
297
- * [Terminal 2]:
413
+ - [Terminal 2]:
298
414
 
299
415
  ```shell
300
416
  npm run test:puppeteer
301
417
  ```
302
418
 
303
- * IDE:
304
- * Many of the IDE's on the market can run tests via the UI. The following is an example configuration for intellij. Once set you can right-click on the test name or file and select the run option.
419
+ - IDE:
420
+ - Many of the IDE's on the market can run tests via the UI. The following is an example configuration for intellij. Once set you can right-click on the test name or file and select the run option.
305
421
  ![ixbrl-viewer](https://raw.githubusercontent.com/Arelle/ixbrl-viewer/master/tests/puppeteer/puppeteer_test_run_via_intellij.jpg)
306
- * Debug runs with breakpoints are also typically supported.
422
+ - Debug runs with breakpoints are also typically supported.
423
+
424
+ ## 👥 Contributors
425
+
426
+ <div align="center">
427
+ <a href="https://github.com/Arelle/ixbrl-viewer/graphs/contributors">
428
+ <img src="https://contrib.rocks/image?repo=Arelle/ixbrl-viewer&max=100&columns=10" style="margin: 5px;" />
429
+ </a>
430
+ <p>Join our community and become a contributor today! 🚀 </p>
431
+ </div>
432
+
433
+ ## License
434
+
435
+ [Apache License 2.0][license]
436
+
437
+ [license]: https://arelle-ixbrl-viewer.readthedocs.io/en/latest/license.html