ixbrl-viewer 1.4.67__py3-none-any.whl → 1.4.69__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 ixbrl-viewer might be problematic. Click here for more details.

Files changed (30) hide show
  1. iXBRLViewerPlugin/_version.py +2 -2
  2. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
  3. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js.LICENSE.txt +1 -1
  4. {ixbrl_viewer-1.4.67.dist-info → ixbrl_viewer-1.4.69.dist-info}/METADATA +7 -8
  5. {ixbrl_viewer-1.4.67.dist-info → ixbrl_viewer-1.4.69.dist-info}/RECORD +10 -30
  6. {ixbrl_viewer-1.4.67.dist-info → ixbrl_viewer-1.4.69.dist-info}/top_level.txt +0 -1
  7. tests/__init__.py +0 -0
  8. tests/puppeteer/framework/core_elements.js +0 -117
  9. tests/puppeteer/framework/page_objects/doc_frame.js +0 -105
  10. tests/puppeteer/framework/page_objects/fact_details_panel.js +0 -112
  11. tests/puppeteer/framework/page_objects/search_panel.js +0 -73
  12. tests/puppeteer/framework/page_objects/toolbar.js +0 -18
  13. tests/puppeteer/framework/utils.js +0 -3
  14. tests/puppeteer/framework/viewer_page.js +0 -103
  15. tests/puppeteer/puppeteer_test_run_via_intellij.jpg +0 -0
  16. tests/puppeteer/test_filings/filing_documents_smoke_test.zip +0 -0
  17. tests/puppeteer/test_filings/highlights.zip +0 -0
  18. tests/puppeteer/tests/fact_properties.test.js +0 -84
  19. tests/puppeteer/tests/highlight.test.js +0 -186
  20. tests/puppeteer/tests/search.test.js +0 -86
  21. tests/puppeteer/tools/generate.sh +0 -15
  22. tests/unit_tests/__init__.py +0 -0
  23. tests/unit_tests/iXBRLViewerPlugin/__init__.py +0 -0
  24. tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py +0 -41
  25. tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py +0 -801
  26. tests/unit_tests/iXBRLViewerPlugin/test_xhtmlserialize.py +0 -310
  27. {ixbrl_viewer-1.4.67.dist-info → ixbrl_viewer-1.4.69.dist-info}/WHEEL +0 -0
  28. {ixbrl_viewer-1.4.67.dist-info → ixbrl_viewer-1.4.69.dist-info}/entry_points.txt +0 -0
  29. {ixbrl_viewer-1.4.67.dist-info → ixbrl_viewer-1.4.69.dist-info}/licenses/LICENSE.md +0 -0
  30. {ixbrl_viewer-1.4.67.dist-info → ixbrl_viewer-1.4.69.dist-info}/licenses/NOTICE +0 -0
@@ -1,801 +0,0 @@
1
- import io
2
- import json
3
- import logging
4
- import os
5
- from collections import defaultdict
6
- from unittest.mock import Mock, patch
7
-
8
- import pytest
9
- from arelle import XbrlConst
10
- from arelle.ModelDocument import Type
11
- from arelle.ModelValue import qname
12
- from lxml import etree
13
-
14
- from .mock_arelle import mock_arelle
15
-
16
- mock_arelle()
17
-
18
- from iXBRLViewerPlugin.iXBRLViewer import NamespaceMap, IXBRLViewerBuilder, iXBRLViewerFile
19
-
20
- class TestNamespaceMap:
21
-
22
- def test_getPrefix_with_none(self):
23
- """
24
- Tests NamespaceMap.getPrefix with None. Should return generated prefix.
25
- """
26
- ns_map = NamespaceMap()
27
- result = ns_map.getPrefix(None)
28
- assert result == 'ns0'
29
-
30
- def test_getPrefix_with_none_with_prefix(self):
31
- """
32
- Tests NamespaceMap.getPrefix with None. Should return specified prefix.
33
- """
34
- ns_map = NamespaceMap()
35
- prefix = 'prefix'
36
- result = ns_map.getPrefix(None, prefix)
37
- assert result == prefix
38
-
39
- def test_getPrefix_with_namespace(self):
40
- """
41
- Tests NamespaceMap.getPrefix for 'namespace'. Should return generated
42
- prefix.
43
- """
44
- ns_map = NamespaceMap()
45
- namespace = 'namespace'
46
- result = ns_map.getPrefix(namespace)
47
- assert result == 'ns0'
48
-
49
- def test_getPrefix_with_namespace_with_prefix(self):
50
- """
51
- Tests NamespaceMap.getPrefix with 'namespace' with preferred prefix.
52
- Should return specified prefix.
53
- """
54
- ns_map = NamespaceMap()
55
- namespace = 'namespace'
56
- prefix = 'prefix'
57
- result = ns_map.getPrefix(namespace, prefix)
58
- assert result == prefix
59
-
60
- def test_getPrefix_subsequent_call_with_namespace(self):
61
- """
62
- Tests NamespaceMap.getPrefix twice with 'namespace'. Should return same
63
- generated prefix.
64
- """
65
- ns_map = NamespaceMap()
66
- namespace = 'namespace'
67
- result = ns_map.getPrefix(namespace)
68
- assert result == 'ns0'
69
- result_2 = ns_map.getPrefix(namespace)
70
- assert result_2 == 'ns0'
71
-
72
- def test_getPrefix_subsequent_call_with_namespace_and_prefix(self):
73
- """
74
- Tests NamespaceMap.getPrefix twice with 'namespace' and specified
75
- prefix. Should return same specified prefix.
76
- """
77
- ns_map = NamespaceMap()
78
- namespace = 'namespace'
79
- prefix = 'prefix'
80
- result = ns_map.getPrefix(namespace, prefix)
81
- assert result == prefix
82
- result_2 = ns_map.getPrefix(namespace, prefix)
83
- assert result_2 == prefix
84
-
85
- def test_getPrefix_subsequent_call_with_two_namespaces_and_prefix(self):
86
- """
87
- Tests NamespaceMap.getPrefix with two namespaces. Should return
88
- sequential generated prefixes.
89
- """
90
- ns_map = NamespaceMap()
91
- namespace_1 = 'namespace_1'
92
- namespace_2 = 'namespace_2'
93
- result = ns_map.getPrefix(namespace_1)
94
- assert result == 'ns0'
95
- result_2 = ns_map.getPrefix(namespace_2)
96
- assert result_2 == 'ns1'
97
-
98
-
99
- class TestIXBRLViewer:
100
-
101
- def setup_method(self, method):
102
- self.usd_qname = Mock(
103
- localName='USD',
104
- prefix='iso4217',
105
- namespaceURI='http://www.xbrl.org/2003/iso4217'
106
- )
107
-
108
- self.monetary_type = Mock(
109
- qname = Mock(
110
- localName="monetaryItemType",
111
- prefix="xbrli",
112
- namespaceURI="http://www.xbrl.org/2003/instance"
113
- )
114
- )
115
-
116
- self.string_type = Mock(
117
- qname = Mock(
118
- localName="stringItemType",
119
- prefix="xbrli",
120
- namespaceURI="http://www.xbrl.org/2003/instance"
121
- )
122
- )
123
-
124
- self.integer_simple_type = Mock(
125
- qname = Mock(
126
- localName="integer",
127
- prefix="xs",
128
- namespaceURI="http://www.w3.org/2001/XMLSchema"
129
- )
130
- )
131
-
132
- self.usd_unit = Mock(
133
- measures = ([self.usd_qname],[])
134
- )
135
-
136
- self.null_units = Mock(
137
- measures = ([],[])
138
- )
139
-
140
- self.cash_concept = Mock(
141
- qname=Mock(
142
- localName='Cash',
143
- prefix='us-gaap',
144
- namespaceURI='http://viewer.com'
145
- ),
146
- balance="debit",
147
- isTypedDimension=False,
148
- type=self.monetary_type,
149
- )
150
-
151
- to_concept = Mock(
152
- qname=Mock(
153
- localName='to_concept',
154
- prefix='us-gaap',
155
- namespaceURI='http://viewer.com'
156
- ),
157
- balance="credit",
158
- isTypedDimension=False,
159
- type=self.monetary_type,
160
- )
161
- from_concept = Mock(
162
- qname=Mock(
163
- localName='from_concept',
164
- prefix='us-gaap',
165
- namespaceURI='http://viewer.com'
166
- ),
167
- balance=None,
168
- isTypedDimension=False,
169
- type=self.monetary_type,
170
- )
171
-
172
- dimension_concept = Mock(
173
- qname=Mock(
174
- localName='dimension',
175
- prefix='us-gaap',
176
- namespaceURI='http://viewer.com'
177
- ),
178
- balance=None,
179
- isTypedDimension=False,
180
- type=self.string_type,
181
- )
182
-
183
- typed_dimension_domain_concept = Mock(
184
- qname=Mock(
185
- localName='typed_dimension_domain',
186
- prefix='us-gaap',
187
- namespaceURI='http://viewer.com'
188
- ),
189
- balance=None,
190
- isTypedDimension=False,
191
- type=self.string_type,
192
- )
193
-
194
- typed_dimension_concept = Mock(
195
- qname=Mock(
196
- localName='typed_dimension',
197
- prefix='us-gaap',
198
- namespaceURI='http://viewer.com'
199
- ),
200
- balance=None,
201
- isTypedDimension=True,
202
- typedDomainElement=typed_dimension_domain_concept,
203
- type=self.integer_simple_type,
204
- )
205
-
206
- member_concept = Mock(
207
- qname=Mock(
208
- localName='member',
209
- prefix='us-gaap',
210
- namespaceURI='http://viewer.com'
211
- ),
212
- balance=None,
213
- isTypedDimension=False,
214
- type=self.string_type,
215
- )
216
-
217
- rel = Mock(
218
- fromModelObject=from_concept,
219
- toModelObject=to_concept,
220
- weight=1
221
- )
222
-
223
- dimension = Mock(
224
- dimensionQname=dimension_concept.qname,
225
- memberQname=member_concept.qname,
226
- dimension=dimension_concept,
227
- member=member_concept
228
- )
229
-
230
- typed_dimension = Mock(
231
- dimensionQname=typed_dimension_concept.qname,
232
- memberQname=None,
233
- dimension=typed_dimension_concept,
234
- typedMember=Mock(text='typedDimension')
235
- )
236
-
237
- dimension_missing_member = Mock(
238
- dimensionQname=dimension_concept.qname,
239
- memberQname=None,
240
- dimension=dimension_concept,
241
- typedMember=None
242
- )
243
-
244
- def isoformat_effect():
245
- return '01-01-19T00:00:00'
246
-
247
- context_1 = Mock(
248
- entityIdentifier=('scheme', 'ident'),
249
- qnameDims={'d': dimension},
250
- isInstantPeriod=False,
251
- isStartEndPeriod=True,
252
- startDatetime=Mock(isoformat=isoformat_effect),
253
- endDatetime=Mock(isoformat=isoformat_effect)
254
- )
255
-
256
- context_2 = Mock(
257
- entityIdentifier=('scheme', 'ident'),
258
- qnameDims={},
259
- isInstantPeriod=None,
260
- isStartEndPeriod=None
261
- )
262
-
263
- context_with_typed_dimension = Mock(
264
- entityIdentifier=('scheme', 'ident'),
265
- qnameDims={'d': typed_dimension},
266
- isInstantPeriod=False,
267
- isStartEndPeriod=True,
268
- startDatetime=Mock(isoformat=isoformat_effect),
269
- endDatetime=Mock(isoformat=isoformat_effect)
270
- )
271
-
272
- context_with_missing_member_on_dimension = Mock(
273
- entityIdentifier=('scheme', 'ident'),
274
- qnameDims={'d': dimension_missing_member},
275
- isInstantPeriod=False,
276
- isStartEndPeriod=True,
277
- startDatetime=Mock(isoformat=isoformat_effect),
278
- endDatetime=Mock(isoformat=isoformat_effect)
279
- )
280
-
281
- fact_1 = Mock(
282
- id='fact_id1',
283
- qname=self.cash_concept.qname,
284
- value=100,
285
- isNumeric=False,
286
- isTuple=False,
287
- context=context_1,
288
- concept=self.cash_concept,
289
- format='format'
290
- )
291
-
292
- fact_2 = Mock(
293
- id='fact_id2',
294
- qname=self.cash_concept.qname,
295
- concept=self.cash_concept,
296
- context=context_2,
297
- isNumeric=True,
298
- isTuple=False,
299
- unit=self.usd_unit,
300
- value=None,
301
- decimals=None,
302
- precision=None,
303
- format=None
304
- )
305
-
306
- fact_3 = Mock(
307
- id='fact_id3',
308
- qname=self.cash_concept.qname,
309
- concept=self.cash_concept,
310
- context=context_2,
311
- isNumeric=True,
312
- isTuple=False,
313
- unit=self.null_units,
314
- value=None,
315
- decimals=None,
316
- precision=None,
317
- format=None
318
- )
319
-
320
- fact_with_typed_dimension = Mock(
321
- id='fact_typed_dimension',
322
- qname=self.cash_concept.qname,
323
- value=10,
324
- isNumeric=False,
325
- isTuple=False,
326
- context=context_with_typed_dimension,
327
- concept=self.cash_concept,
328
- format='format'
329
- )
330
-
331
- fact_with_missing_member_on_dimension = Mock(
332
- id='fact_dimension_missing_member',
333
- qname=self.cash_concept.qname,
334
- value=1000,
335
- isNumeric=False,
336
- isTuple=False,
337
- context=context_with_missing_member_on_dimension,
338
- concept=self.cash_concept,
339
- format='format'
340
- )
341
-
342
- file_1 = Mock(
343
- filename='something/reports/001.jpg'
344
- )
345
-
346
- file_2 = Mock(
347
- filename='something/reports/002.jpg'
348
- )
349
-
350
- fs = Mock(
351
- filelist = [file_1, file_2]
352
- )
353
-
354
- file_source = Mock(
355
- fs = fs
356
- )
357
-
358
- def creationSoftwareMatches_effect(text):
359
- return ["Example Software Name"]
360
-
361
- def fromModelObjects_effect(concept):
362
- return []
363
-
364
- def relationshipSet_effect(self, *args):
365
- return Mock(
366
- fromModelObject=fromModelObjects_effect,
367
- modelRelationships=[rel]
368
- )
369
-
370
- def info_effect(info, msg):
371
- # This is a no op for logging
372
- pass
373
-
374
- baseSets = defaultdict(list)
375
- baseSets[('http://www.xbrl.org/2003/arcrole/summation-item', 'ELR', 'linkqname', 'arcqname')] = []
376
- baseSets[("http://xbrl.org/int/dim/arcrole/dimension-default", 'ELR', 'linkqname', 'arcqname')] = []
377
- baseSets[("http://www.xbrl.org/2003/arcrole/parent-child", 'ELR', 'linkqname', 'arcqname')] = []
378
-
379
- roleTypes = defaultdict(list)
380
- roleTypes['ELR'] = [Mock(definition = "ELR Label")]
381
-
382
- root = etree.Element('root')
383
- etree.SubElement(root, '{http://www.w3.org/1999/xhtml}body')
384
-
385
- self.modelDocument = Mock(
386
- xmlDocument=etree.ElementTree(root),
387
- filepath='a.html',
388
- referencesDocument={
389
- "xmlDocument":etree.ElementTree(root),
390
- "filepath":'a.html',
391
- "objectIndex":0,
392
- "type":Type.INLINEXBRL,
393
- },
394
- ixdsTarget=None,
395
- )
396
-
397
- self.modelDocumentInlineSet = Mock(
398
- referencesDocument={
399
- Mock(
400
- xmlDocument=etree.ElementTree(root),
401
- filepath='a.html',
402
- objectIndex=0,
403
- type=Type.INLINEXBRL,
404
- ): [],
405
- Mock(
406
- xmlDocument=etree.ElementTree(root),
407
- filepath='b.html',
408
- objectIndex=1,
409
- type=Type.INLINEXBRL,
410
- ): [],
411
- Mock(
412
- xmlDocument=etree.ElementTree(root),
413
- filepath='a.xsd',
414
- objectIndex=2,
415
- type=Type.SCHEMA,
416
- ): [],
417
- },
418
- filepath=self.modelDocument.filepath,
419
- type=Type.INLINEXBRLDOCUMENTSET,
420
- ixdsTarget=None,
421
- )
422
-
423
-
424
- def urlDocEntry(path, docType, linkQName=None):
425
- return path, Mock(
426
- creationSoftwareMatches=creationSoftwareMatches_effect,
427
- type=docType,
428
- basename=os.path.basename(path),
429
- xmlRootElement=Mock(
430
- iterchildren=Mock(
431
- return_value=[
432
- Mock(qname=linkQName)] if linkQName else []
433
- )
434
- )
435
- )
436
-
437
- self.modelXbrl_1 = Mock(
438
- relationshipSet=relationshipSet_effect,
439
- relationshipSets={},
440
- baseSets=baseSets,
441
- roleTypes=roleTypes,
442
- facts=[fact_1, fact_with_typed_dimension, fact_with_missing_member_on_dimension],
443
- fileSource=file_source,
444
- info=info_effect,
445
- modelDocument=self.modelDocument,
446
- ixdsTarget=None,
447
- urlDocs=dict((
448
- urlDocEntry('/filesystem/local-inline.htm', Type.INLINEXBRL),
449
- urlDocEntry('https://example.com/remote-inline.htm', Type.INLINEXBRL),
450
- urlDocEntry('/filesystem/local-docset/_IXDS', Type.INLINEXBRLDOCUMENTSET),
451
- urlDocEntry('https://example.com/remote-docset/_IXDS', Type.INLINEXBRLDOCUMENTSET),
452
- urlDocEntry('/filesystem/local-schema.xsd', Type.SCHEMA),
453
- urlDocEntry('https://example.com/remote-schema.xsd', Type.SCHEMA),
454
- urlDocEntry('/filesystem/local-label-linkbase.xml', Type.LINKBASE, XbrlConst.qnLinkLabelLink),
455
- urlDocEntry('https://example.com/remote-label-linkbase.xml', Type.LINKBASE, XbrlConst.qnLinkLabelLink),
456
- urlDocEntry('/filesystem/local-pres-linkbase.xml', Type.LINKBASE, XbrlConst.qnLinkPresentationLink),
457
- urlDocEntry('https://example.com/remote-pres-linkbase.xml', Type.LINKBASE, XbrlConst.qnLinkPresentationLink),
458
- urlDocEntry('/filesystem/local-calc-linkbase.xml', Type.LINKBASE, XbrlConst.qnLinkCalculationLink),
459
- urlDocEntry('https://example.com/remote-calc-linkbase.xml', Type.LINKBASE, XbrlConst.qnLinkCalculationLink),
460
- urlDocEntry('/filesystem/local-def-linkbase.xml', Type.LINKBASE, XbrlConst.qnLinkDefinitionLink),
461
- urlDocEntry('https://example.com/remote-def-linkbase.xml', Type.LINKBASE, XbrlConst.qnLinkDefinitionLink),
462
- urlDocEntry('/filesystem/local-ref-linkbase.xml', Type.LINKBASE, XbrlConst.qnLinkReferenceLink),
463
- urlDocEntry('https://example.com/remote-ref-linkbase.xml', Type.LINKBASE, XbrlConst.qnLinkReferenceLink),
464
- urlDocEntry('/filesystem/local-unrecognized-linkbase.xml', Type.LINKBASE, qname("{http://www.example.org/linkbase}link:unrecognizedLink")),
465
- urlDocEntry('https://example.com/remote-unrecognized-linkbase.xml', Type.LINKBASE, qname("{http://www.example.org/linkbase}link:unrecognizedLink")),
466
- ))
467
- )
468
- self.modelXbrl_2 = Mock(
469
- relationshipSet=relationshipSet_effect,
470
- relationshipSets={},
471
- baseSets=baseSets,
472
- roleTypes=roleTypes,
473
- facts=[fact_2, fact_3],
474
- fileSource=file_source,
475
- info=info_effect,
476
- modelDocument=self.modelDocument,
477
- ixdsTarget=None,
478
- urlDocs={}
479
- )
480
- self.modelXbrlDocSet = Mock(
481
- relationshipSet=relationshipSet_effect,
482
- relationshipSets={},
483
- baseSets=baseSets,
484
- roleTypes=roleTypes,
485
- facts=[fact_1, fact_with_typed_dimension, fact_with_missing_member_on_dimension],
486
- fileSource=file_source,
487
- info=info_effect,
488
- modelDocument=self.modelDocumentInlineSet,
489
- ixdsTarget=None,
490
- urlDocs={}
491
- )
492
-
493
- self.cash_concept.modelXbrl = self.modelXbrl_1
494
- to_concept.modelXbrl = self.modelXbrl_1
495
- from_concept.modelXbrl = self.modelXbrl_1
496
- dimension_concept.modelXbrl = self.modelXbrl_1
497
- typed_dimension_concept.modelXbrl = self.modelXbrl_1
498
- typed_dimension_domain_concept.modelXbrl = self.modelXbrl_1
499
- member_concept.modelXbrl = self.modelXbrl_1
500
-
501
- self.logRecordBuffer = []
502
- self.cntlr_mock = Mock(
503
- logHandler = Mock(
504
- logRecordBuffer = self.logRecordBuffer
505
- )
506
- )
507
- self.builder_1 = IXBRLViewerBuilder(self.cntlr_mock)
508
- self.builder_doc_set = IXBRLViewerBuilder(self.cntlr_mock)
509
-
510
-
511
- @patch('arelle.XbrlConst.conceptLabel', 'http://www.xbrl.org/2003/arcrole/concept-label')
512
- @patch('arelle.XbrlConst.conceptReference', 'http://www.xbrl.org/2003/arcrole/concept-reference')
513
- def test_addConcept_simple_case(self):
514
- builder = IXBRLViewerBuilder(Mock())
515
- builder.currentTargetReport = builder.newTargetReport(None)
516
- builder.addSourceReport()["targetReports"].append(builder.currentTargetReport)
517
- builder.addConcept(self.modelXbrl_1, self.cash_concept)
518
- assert builder.taxonomyData["sourceReports"][0]["targetReports"][0].get('concepts').get('us-gaap:Cash')
519
-
520
- @patch('arelle.XbrlConst.parentChild', 'http://www.xbrl.org/2003/arcrole/parent-child')
521
- @patch('arelle.XbrlConst.summationItem', 'http://www.xbrl.org/2003/arcrole/summation-item')
522
- def test_getRelationships_simple_case(self):
523
- modelXbrl = Mock(baseSets=defaultdict(list), relationshipSets={})
524
- builder = IXBRLViewerBuilder(Mock())
525
- result = builder.getRelationships(modelXbrl)
526
- assert result == {}
527
-
528
- @patch('arelle.XbrlConst.parentChild', 'http://www.xbrl.org/2003/arcrole/parent-child')
529
- @patch('arelle.XbrlConst.summationItem', 'http://www.xbrl.org/2003/arcrole/summation-item')
530
- def test_getRelationships_returns_a_rel(self):
531
- builder = IXBRLViewerBuilder(Mock())
532
- builder.currentTargetReport = builder.newTargetReport(None)
533
- result = builder.getRelationships(self.modelXbrl_1)
534
- roleMap = builder.roleMap
535
- siPrefix = roleMap.getPrefix('http://www.xbrl.org/2003/arcrole/summation-item')
536
- assert result.get(siPrefix).get(roleMap.getPrefix('ELR')).get('us-gaap:from_concept')
537
-
538
- def test_addRoleDefinition_no_definition(self):
539
- """
540
- Adding an ELR with no definition should result in no entry in the roleDefs map
541
- """
542
- elr = "http://example.com/unknownELR"
543
- builder = IXBRLViewerBuilder(Mock())
544
- builder.currentTargetReport = builder.newTargetReport(None)
545
- builder.addRoleDefinition(self.modelXbrl_1, elr)
546
- elrPrefix = builder.roleMap.getPrefix(elr)
547
- assert builder.currentTargetReport.get('roleDefs').get(elrPrefix) is None
548
-
549
- def test_addRoleDefinition_with_definition(self):
550
- """
551
- Adding an ELR with a definition should result in an "en" label with the definition as its value.
552
- """
553
- elr = "ELR"
554
- builder = IXBRLViewerBuilder(Mock())
555
- builder.currentTargetReport = builder.newTargetReport(None)
556
- builder.addRoleDefinition(self.modelXbrl_1, elr)
557
- elrPrefix = builder.roleMap.getPrefix(elr)
558
- assert builder.currentTargetReport.get('roleDefs').get(elrPrefix).get("en") == "ELR Label"
559
-
560
- @patch('arelle.XbrlConst.conceptLabel', 'http://www.xbrl.org/2003/arcrole/concept-label')
561
- @patch('arelle.XbrlConst.conceptReference', 'http://www.xbrl.org/2003/arcrole/concept-reference')
562
- @patch('arelle.XbrlConst.dimensionDefault', 'http://xbrl.org/int/dim/arcrole/dimension-default')
563
- @patch('arelle.XbrlConst.parentChild', 'http://www.xbrl.org/2003/arcrole/parent-child')
564
- @patch('arelle.XbrlConst.summationItem', 'http://www.xbrl.org/2003/arcrole/summation-item')
565
- @patch('arelle.XbrlConst.standardLabel', 'http://www.xbrl.org/2003/role/label')
566
- @patch('arelle.XbrlConst.documentationLabel', 'http://www.xbrl.org/2003/role/documentation')
567
- def test_createViewerWithValidation(self):
568
- js_uri = 'ixbrlviewer.js'
569
-
570
- error1 = logging.LogRecord("arelle", logging.ERROR, "", 0, "Error message", {}, None)
571
- error1.messageCode = "code1"
572
- self.logRecordBuffer.append(error1)
573
-
574
- builder = IXBRLViewerBuilder(self.cntlr_mock)
575
- builder.processModel(self.modelXbrl_1)
576
- result = builder.createViewer(js_uri)
577
- assert len(result.files) == 1
578
- body = result.files[0].xmlDocument.getroot()[0]
579
- assert body[0].text == 'BEGIN IXBRL VIEWER EXTENSIONS'
580
- assert body[1].attrib.get('src') == js_uri
581
- assert body[1].attrib.get('type') == 'text/javascript'
582
- assert body[2].attrib.get('type') == 'application/x.ixbrl-viewer+json'
583
- assert body[3].text == 'END IXBRL VIEWER EXTENSIONS'
584
-
585
- jsdata = json.loads(body[2].text)
586
- errors = jsdata["validation"]
587
- assert errors == [{"sev": "ERROR", "msg": "Error message", "code": "code1" }]
588
- assert set(jsdata["sourceReports"][0]["targetReports"][0]["facts"]) == {"fact_id1", "fact_typed_dimension", "fact_dimension_missing_member"}
589
- assert jsdata["sourceReports"][0]["targetReports"][0]["softwareCredits"] == ["Example Software Name"]
590
-
591
- @patch('arelle.XbrlConst.conceptLabel', 'http://www.xbrl.org/2003/arcrole/concept-label')
592
- @patch('arelle.XbrlConst.conceptReference', 'http://www.xbrl.org/2003/arcrole/concept-reference')
593
- @patch('arelle.XbrlConst.parentChild', 'http://www.xbrl.org/2003/arcrole/parent-child')
594
- @patch('arelle.XbrlConst.summationItem', 'http://www.xbrl.org/2003/arcrole/summation-item')
595
- @patch('arelle.XbrlConst.standardLabel', 'http://www.xbrl.org/2003/role/label')
596
- @patch('arelle.XbrlConst.documentationLabel', 'http://www.xbrl.org/2003/role/documentation')
597
- @patch('arelle.XbrlConst.dimensionDefault', 'http://xbrl.org/int/dim/arcrole/dimension-default')
598
- def test_createViewer(self):
599
- js_uri = 'ixbrlviewer.js'
600
- builder = IXBRLViewerBuilder(self.cntlr_mock)
601
- builder.processModel(self.modelXbrl_1)
602
- result = builder.createViewer(js_uri, showValidations = False)
603
- assert len(result.files) == 1
604
- body = result.files[0].xmlDocument.getroot()[0]
605
- assert body[0].text, 'BEGIN IXBRL VIEWER EXTENSIONS'
606
- assert body[1].attrib.get('src') == js_uri
607
- assert body[1].attrib.get('type') == 'text/javascript'
608
- assert body[2].attrib.get('type') == 'application/x.ixbrl-viewer+json'
609
- assert body[3].text == 'END IXBRL VIEWER EXTENSIONS'
610
-
611
- jsdata = json.loads(body[2].text)
612
- assert "validation" not in jsdata
613
- reportData = jsdata["sourceReports"][0]["targetReports"][0]
614
- assert set(reportData["facts"]) == {"fact_id1", "fact_typed_dimension", "fact_dimension_missing_member"}
615
- assert reportData["concepts"] == {
616
- 'us-gaap:Cash': {'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:monetaryItemType', 'b': 'debit'},
617
- 'us-gaap:from_concept': {'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:monetaryItemType'},
618
- 'us-gaap:to_concept': {'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:monetaryItemType', 'b': 'credit'},
619
- 'us-gaap:dimension': {'d': 'e', 'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:stringItemType'},
620
- 'us-gaap:member': {'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:stringItemType'},
621
- 'us-gaap:typed_dimension_domain': {'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:stringItemType'},
622
- 'us-gaap:typed_dimension': {'d': 't', 'e': True, 't': True, 'labels': {}, 'td': 'us-gaap:typed_dimension_domain', 'dt': 'xs:integer'},
623
- }
624
- assert reportData["localDocs"] == {
625
- 'local-inline.htm': ['inline'],
626
- 'local-schema.xsd': ['schema'],
627
- 'local-pres-linkbase.xml': ['presLinkbase'],
628
- 'local-calc-linkbase.xml': ['calcLinkbase'],
629
- 'local-def-linkbase.xml': ['defLinkbase'],
630
- 'local-label-linkbase.xml': ['labelLinkbase'],
631
- 'local-ref-linkbase.xml': ['refLinkbase'],
632
- 'local-unrecognized-linkbase.xml': ['unrecognizedLinkbase'],
633
- }
634
-
635
- assert jsdata["sourceReports"][0]["docSetFiles"] == ["a.html"]
636
-
637
- @patch('arelle.XbrlConst.conceptLabel', 'http://www.xbrl.org/2003/arcrole/concept-label')
638
- @patch('arelle.XbrlConst.conceptReference', 'http://www.xbrl.org/2003/arcrole/concept-reference')
639
- @patch('arelle.XbrlConst.parentChild', 'http://www.xbrl.org/2003/arcrole/parent-child')
640
- @patch('arelle.XbrlConst.summationItem', 'http://www.xbrl.org/2003/arcrole/summation-item')
641
- @patch('arelle.XbrlConst.standardLabel', 'http://www.xbrl.org/2003/role/label')
642
- @patch('arelle.XbrlConst.documentationLabel', 'http://www.xbrl.org/2003/role/documentation')
643
- @patch('arelle.XbrlConst.dimensionDefault', 'http://xbrl.org/int/dim/arcrole/dimension-default')
644
- def test_createStubViewer(self):
645
- js_uri = 'ixbrlviewer.js'
646
- builder = IXBRLViewerBuilder(self.cntlr_mock, useStubViewer = True)
647
- builder.processModel(self.modelXbrl_1)
648
- result = builder.createViewer(js_uri, showValidations = False)
649
- assert len(result.files) == 2
650
- body = result.files[0].xmlDocument.getroot().find('{http://www.w3.org/1999/xhtml}body')
651
- assert body[0].text == 'BEGIN IXBRL VIEWER EXTENSIONS'
652
- assert body[1].attrib.get('src') == js_uri
653
- assert body[1].attrib.get('type') == 'text/javascript'
654
- assert body[2].attrib.get('type') == 'application/x.ixbrl-viewer+json'
655
- assert body[3].text == 'END IXBRL VIEWER EXTENSIONS'
656
-
657
- jsdata = json.loads(body[2].text)
658
- assert "validation" not in jsdata
659
- reportData = jsdata["sourceReports"][0]["targetReports"][0]
660
- assert set(reportData["facts"]) == {"fact_id1", "fact_typed_dimension", "fact_dimension_missing_member"}
661
- assert reportData["concepts"] == {
662
- 'us-gaap:Cash': {'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:monetaryItemType', 'b': 'debit'},
663
- 'us-gaap:from_concept': {'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:monetaryItemType'},
664
- 'us-gaap:to_concept': {'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:monetaryItemType', 'b': 'credit'},
665
- 'us-gaap:dimension': {'d': 'e', 'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:stringItemType'},
666
- 'us-gaap:member': {'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:stringItemType'},
667
- 'us-gaap:typed_dimension_domain': {'e': True, 't': True, 'labels': {}, 'dt': 'xbrli:stringItemType'},
668
- 'us-gaap:typed_dimension': {'d': 't', 'e': True, 't': True, 'labels': {}, 'td': 'us-gaap:typed_dimension_domain', 'dt': 'xs:integer'},
669
- }
670
- assert reportData["localDocs"] == {
671
- 'local-inline.htm': ['inline'],
672
- 'local-schema.xsd': ['schema'],
673
- 'local-pres-linkbase.xml': ['presLinkbase'],
674
- 'local-calc-linkbase.xml': ['calcLinkbase'],
675
- 'local-def-linkbase.xml': ['defLinkbase'],
676
- 'local-label-linkbase.xml': ['labelLinkbase'],
677
- 'local-ref-linkbase.xml': ['refLinkbase'],
678
- 'local-unrecognized-linkbase.xml': ['unrecognizedLinkbase'],
679
- }
680
-
681
- assert jsdata["sourceReports"][0]["docSetFiles"] == [ "a.html" ]
682
-
683
- @patch('arelle.XbrlConst.conceptLabel', 'http://www.xbrl.org/2003/arcrole/concept-label')
684
- @patch('arelle.XbrlConst.conceptReference', 'http://www.xbrl.org/2003/arcrole/concept-reference')
685
- @patch('arelle.XbrlConst.parentChild', 'http://www.xbrl.org/2003/arcrole/parent-child')
686
- @patch('arelle.XbrlConst.summationItem', 'http://www.xbrl.org/2003/arcrole/summation-item')
687
- @patch('arelle.XbrlConst.standardLabel', 'http://www.xbrl.org/2003/role/label')
688
- @patch('arelle.XbrlConst.documentationLabel', 'http://www.xbrl.org/2003/role/documentation')
689
- @patch('arelle.XbrlConst.dimensionDefault', 'http://xbrl.org/int/dim/arcrole/dimension-default')
690
- def test_createViewer_docset(self):
691
- js_uri = 'ixbrlviewer.js'
692
- self.builder_doc_set.processModel(self.modelXbrlDocSet)
693
- result = self.builder_doc_set.createViewer(js_uri, showValidations=False)
694
- assert len(result.files) == 2
695
- body = result.files[0].xmlDocument.getroot()[0]
696
- assert body[0].text == 'BEGIN IXBRL VIEWER EXTENSIONS'
697
- assert body[1].attrib.get('src') == js_uri
698
- assert body[1].attrib.get('type') == 'text/javascript'
699
- assert body[2].attrib.get('type') == 'application/x.ixbrl-viewer+json'
700
- assert body[3].text == 'END IXBRL VIEWER EXTENSIONS'
701
-
702
- jsdata = json.loads(body[2].text)
703
- assert "validation" not in jsdata
704
- reportData = jsdata["sourceReports"][0]["targetReports"][0]
705
- assert set(reportData["facts"]) == {"fact_id1", "fact_typed_dimension", "fact_dimension_missing_member"}
706
-
707
- assert jsdata["sourceReports"][0]["docSetFiles"] == [
708
- 'a.html',
709
- 'b.html'
710
- ]
711
-
712
- @patch('arelle.XbrlConst.conceptLabel', 'http://www.xbrl.org/2003/arcrole/concept-label')
713
- @patch('arelle.XbrlConst.conceptReference', 'http://www.xbrl.org/2003/arcrole/concept-reference')
714
- @patch('arelle.XbrlConst.parentChild', 'http://www.xbrl.org/2003/arcrole/parent-child')
715
- @patch('arelle.XbrlConst.dimensionDefault', 'http://xbrl.org/int/dim/arcrole/dimension-default')
716
- @patch('arelle.XbrlConst.summationItem', 'http://www.xbrl.org/2003/arcrole/summation-item')
717
- @patch('arelle.XbrlConst.standardLabel', 'http://www.xbrl.org/2003/role/label')
718
- @patch('arelle.XbrlConst.documentationLabel', 'http://www.xbrl.org/2003/role/documentation')
719
- def test_createViewer_bad_path(self):
720
- js_uri = 'ixbrlviewer.js'
721
- builder = IXBRLViewerBuilder(self.cntlr_mock)
722
- builder.processModel(self.modelXbrl_2)
723
- result = builder.createViewer(js_uri)
724
- assert len(result.files) == 1
725
- body = result.files[0].xmlDocument.getroot()[0]
726
- assert body[0].text == 'BEGIN IXBRL VIEWER EXTENSIONS'
727
- assert body[1].tag == '{http://www.w3.org/1999/xhtml}script'
728
- assert body[1].prefix is None
729
- assert body[1].attrib.get('src') == js_uri
730
- assert body[1].attrib.get('type') == 'text/javascript'
731
- assert body[2].tag == '{http://www.w3.org/1999/xhtml}script'
732
- assert body[2].prefix is None
733
- assert body[2].attrib.get('type') == 'application/x.ixbrl-viewer+json'
734
- assert body[3].text == 'END IXBRL VIEWER EXTENSIONS'
735
-
736
- jsdata = json.loads(body[2].text)
737
- facts = jsdata["sourceReports"][0]["targetReports"][0]["facts"]
738
- assert facts.keys() == {"fact_id2", "fact_id3"}
739
- assert facts["fact_id2"]["a"]["u"] == "iso4217:USD"
740
- assert facts["fact_id3"]["a"]["u"] is None
741
-
742
- def test_enableFeature_valid(self):
743
- """
744
- Enable a defined feature
745
- """
746
- builder = IXBRLViewerBuilder(Mock(), features={'review': True})
747
- assert builder.taxonomyData["features"] == {'review': True}
748
-
749
- def test_enableFeature_invalid(self):
750
- """
751
- Attempt to enable an undefined feature
752
- """
753
- with pytest.raises(AssertionError, match=rf'^Given feature name `unknown` does not match any defined features'):
754
- IXBRLViewerBuilder(Mock(), features={'unknown': True})
755
-
756
- def test_xhtmlNamespaceHandling(self):
757
- # Check the prefix used for our inserted script tags
758
- tests = (rb'''
759
- <html xmlns="http://www.w3.org/1999/xhtml">
760
- <body>
761
- </body>
762
- </html>
763
- ''',
764
- rb'''
765
- <html xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml">
766
- <body>
767
- </body>
768
- </html>
769
- ''',
770
- # In this case we won't fix the root element to be in the default NS,
771
- # but our <script> tags will be.
772
- rb'''
773
- <xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml">
774
- <body>
775
- </body>
776
- </xhtml:html>
777
- '''
778
- )
779
-
780
- for xmls in tests:
781
- xml = etree.parse(io.BytesIO(xmls))
782
-
783
- js_uri = 'https://example.com/script-url'
784
- viewer_file = iXBRLViewerFile("test.xhtml", xml)
785
- result = self.builder_1.addViewerData(viewer_file, js_uri)
786
-
787
- # addViewerData takes a copy, so original body tag should be empty
788
- original_body = xml.getroot()[0]
789
- assert len(original_body) == 0
790
-
791
- body = viewer_file.xmlDocument.getroot()[0]
792
- assert len(body) == 4
793
- assert body[0].text == 'BEGIN IXBRL VIEWER EXTENSIONS'
794
- assert body[1].tag == '{http://www.w3.org/1999/xhtml}script'
795
- assert body[1].prefix is None
796
- assert body[1].attrib.get('src') == js_uri
797
- assert body[1].attrib.get('type') == 'text/javascript'
798
- assert body[2].tag == '{http://www.w3.org/1999/xhtml}script'
799
- assert body[2].prefix is None
800
- assert body[2].attrib.get('type') == 'application/x.ixbrl-viewer+json'
801
- assert body[3].text == 'END IXBRL VIEWER EXTENSIONS'