ixbrl-viewer 1.4.10__py3-none-any.whl → 1.4.11__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.

@@ -1,4 +1,4 @@
1
1
  # file generated by setuptools_scm
2
2
  # don't change, don't track in version control
3
- __version__ = version = '1.4.10'
4
- __version_tuple__ = version_tuple = (1, 4, 10)
3
+ __version__ = version = '1.4.11'
4
+ __version_tuple__ = version_tuple = (1, 4, 11)
@@ -95,6 +95,7 @@ class IXBRLViewerBuilder:
95
95
  "languages": {},
96
96
  }
97
97
  self.basenameSuffix = basenameSuffix
98
+ self.currentTargetReport = None
98
99
 
99
100
  def enableFeature(self, featureName: str):
100
101
  if featureName in self.taxonomyData["features"]:
@@ -148,21 +149,13 @@ class IXBRLViewerBuilder:
148
149
  if langCode not in self.taxonomyData["languages"]:
149
150
  self.taxonomyData["languages"][langCode] = self.makeLanguageName(langCode)
150
151
 
151
- @property
152
- def currentSourceReportData(self):
153
- return self.taxonomyData["sourceReports"][-1]
154
-
155
- @property
156
- def currentReportData(self):
157
- return self.currentSourceReportData["targetReports"][-1]
158
-
159
152
  def addELR(self, report: ModelXbrl, elr):
160
153
  prefix = self.roleMap.getPrefix(elr)
161
- if self.currentReportData.setdefault("roleDefs",{}).get(prefix, None) is None:
154
+ if self.currentTargetReport.setdefault("roleDefs",{}).get(prefix, None) is None:
162
155
  rts = report.roleTypes.get(elr, [])
163
156
  label = next((rt.definition for rt in rts if rt.definition is not None), None)
164
157
  if label is not None:
165
- self.currentReportData["roleDefs"].setdefault(prefix,{})["en"] = label
158
+ self.currentTargetReport["roleDefs"].setdefault(prefix,{})["en"] = label
166
159
 
167
160
  def addConcept(self, report: ModelXbrl, concept, dimensionType = None):
168
161
  if concept is None:
@@ -170,7 +163,7 @@ class IXBRLViewerBuilder:
170
163
  labelsRelationshipSet = report.relationshipSet(XbrlConst.conceptLabel)
171
164
  labels = labelsRelationshipSet.fromModelObject(concept)
172
165
  conceptName = self.nsmap.qname(concept.qname)
173
- if conceptName not in self.currentReportData["concepts"]:
166
+ if conceptName not in self.currentTargetReport["concepts"]:
174
167
  conceptData = {
175
168
  "labels": { }
176
169
  }
@@ -205,7 +198,7 @@ class IXBRLViewerBuilder:
205
198
  conceptData['td'] = typedDomainName
206
199
  self.addConcept(report, typedDomainElement)
207
200
 
208
- self.currentReportData["concepts"][conceptName] = conceptData
201
+ self.currentTargetReport["concepts"][conceptName] = conceptData
209
202
 
210
203
  def treeWalk(self, rels, item, indent = 0):
211
204
  for r in rels.fromModelObject(item):
@@ -324,7 +317,7 @@ class IXBRLViewerBuilder:
324
317
  if frel.toModelObject is not None:
325
318
  factData.setdefault("fn", []).append(frel.toModelObject.id)
326
319
 
327
- self.currentReportData["facts"][f.id] = factData
320
+ self.currentTargetReport["facts"][f.id] = factData
328
321
  self.addConcept(report, f.concept)
329
322
 
330
323
  def oimUnitString(self, unit):
@@ -348,10 +341,11 @@ class IXBRLViewerBuilder:
348
341
  return "{}/{}".format(numeratorsString, denominatorsString)
349
342
  return numeratorsString
350
343
 
351
- def addViewerToXMLDocument(self, xmlDocument, scriptUrl):
344
+ def addViewerData(self, viewerFile, scriptUrl):
345
+ viewerFile.xmlDocument = deepcopy(viewerFile.xmlDocument)
352
346
  taxonomyDataJSON = self.escapeJSONForScriptTag(json.dumps(self.taxonomyData, indent=1, allow_nan=False))
353
347
 
354
- for child in xmlDocument.getroot():
348
+ for child in viewerFile.xmlDocument.getroot():
355
349
  if child.tag == '{http://www.w3.org/1999/xhtml}body':
356
350
  for body_child in child:
357
351
  if body_child.tag == '{http://www.w3.org/1999/xhtml}script' and body_child.get('type','') == 'application/x.ixbrl-viewer+json':
@@ -383,15 +377,18 @@ class IXBRLViewerBuilder:
383
377
  with open(os.path.join(os.path.dirname(__file__),"stubviewer.html")) as fin:
384
378
  return etree.parse(fin)
385
379
 
386
- def addReport(self):
387
- self.taxonomyData["sourceReports"].append({
388
- "targetReports": [
389
- {
390
- "concepts": {},
391
- "facts": {},
392
- }
393
- ]
394
- })
380
+ def newTargetReport(self):
381
+ return {
382
+ "concepts": {},
383
+ "facts": {},
384
+ }
385
+
386
+ def addSourceReport(self):
387
+ sourceReport = {
388
+ "targetReports": []
389
+ }
390
+ self.taxonomyData["sourceReports"].append(sourceReport)
391
+ return sourceReport
395
392
 
396
393
  def createViewer(self, scriptUrl: str = DEFAULT_VIEWER_PATH, useStubViewer: bool = False, showValidations: bool = True, packageDownloadURL: str = None) -> Optional[iXBRLViewer]:
397
394
  """
@@ -411,59 +408,56 @@ class IXBRLViewerBuilder:
411
408
  self.roleMap.getPrefix(XbrlConst.dimensionDefault, "d-d")
412
409
  self.roleMap.getPrefix(WIDER_NARROWER_ARCROLE, "w-n")
413
410
 
414
- # This is the document that we will embed the JSON taxonomy data in.
415
- # This will be either the first document processed, or the stub document
416
- xmlDocument = None
411
+ sourceReportsByFiles = dict()
412
+
413
+ if useStubViewer:
414
+ iv.addFile(iXBRLViewerFile(DEFAULT_OUTPUT_NAME, self.getStubDocument()))
417
415
 
418
416
  for n, report in enumerate(self.reports):
419
417
  self.footnoteRelationshipSet = ModelRelationshipSet(report, "XBRL-footnotes")
420
- self.addReport()
418
+ self.currentTargetReport = self.newTargetReport()
421
419
  for f in report.facts:
422
420
  self.addFact(report, f)
423
- self.currentReportData["rels"] = self.getRelationships(report)
421
+ self.currentTargetReport["rels"] = self.getRelationships(report)
424
422
 
425
423
  docSetFiles = None
426
424
  report.info("viewer:info", "Creating iXBRL viewer (%d of %d)" % (n+1, len(self.reports)))
427
425
  if report.modelDocument.type == Type.INLINEXBRLDOCUMENTSET:
428
426
  # Sort by object index to preserve order in which files were specified.
429
427
  xmlDocsByFilename = {
430
- os.path.basename(self.outputFilename(doc.filepath)): deepcopy(doc.xmlDocument)
428
+ os.path.basename(self.outputFilename(doc.filepath)): doc.xmlDocument
431
429
  for doc in sorted(report.modelDocument.referencesDocument.keys(), key=lambda x: x.objectIndex)
432
430
  if doc.type == Type.INLINEXBRL
433
431
  }
434
432
  docSetFiles = list(xmlDocsByFilename.keys())
435
433
 
436
- if xmlDocument is None:
437
- if useStubViewer:
438
- xmlDocument = self.getStubDocument()
439
- iv.addFile(iXBRLViewerFile(DEFAULT_OUTPUT_NAME, xmlDocument))
440
- else:
441
- xmlDocument = next(iter(xmlDocsByFilename.values()))
442
-
443
434
  for filename, docSetXMLDoc in xmlDocsByFilename.items():
444
435
  iv.addFile(iXBRLViewerFile(filename, docSetXMLDoc))
445
436
 
446
437
  elif useStubViewer:
447
- if xmlDocument is None:
448
- xmlDocument = self.getStubDocument()
449
- iv.addFile(iXBRLViewerFile(DEFAULT_OUTPUT_NAME, xmlDocument))
450
438
  filename = self.outputFilename(os.path.basename(report.modelDocument.filepath))
451
439
  docSetFiles = [ filename ]
452
440
  iv.addFile(iXBRLViewerFile(filename, report.modelDocument.xmlDocument))
453
441
 
454
442
  else:
443
+ srcFilename = self.outputFilename(os.path.basename(report.modelDocument.filepath))
444
+ docSetFiles = [ srcFilename ]
455
445
  if len(self.reports) == 1:
456
446
  # If there is only a single report, call the output file "xbrlviewer.html"
457
447
  filename = "xbrlviewer.html"
458
448
  else:
459
449
  # Otherwise, preserve filenames
460
- filename = self.outputFilename(os.path.basename(report.modelDocument.filepath))
461
- docSetFiles = [ filename ]
462
- if xmlDocument is None:
463
- xmlDocument = deepcopy(report.modelDocument.xmlDocument)
464
- iv.addFile(iXBRLViewerFile(filename, xmlDocument))
465
- else:
466
- iv.addFile(iXBRLViewerFile(filename, report.modelDocument.xmlDocument))
450
+ filename = srcFilename
451
+ iv.addFile(iXBRLViewerFile(filename, report.modelDocument.xmlDocument))
452
+
453
+ docSetKey = frozenset(docSetFiles)
454
+ sourceReport = sourceReportsByFiles.get(docSetKey)
455
+ if sourceReport is None:
456
+ sourceReport = self.addSourceReport()
457
+ sourceReportsByFiles[docSetKey] = sourceReport
458
+ sourceReport["docSetFiles"] = list(urllib.parse.quote(f) for f in docSetFiles)
459
+
460
+ sourceReport["targetReports"].append(self.currentTargetReport)
467
461
 
468
462
  localDocs = defaultdict(set)
469
463
  for path, doc in report.urlDocs.items():
@@ -482,14 +476,11 @@ class IXBRLViewerBuilder:
482
476
  linkbaseIdentifed = True
483
477
  if not linkbaseIdentifed:
484
478
  localDocs[doc.basename].add(UNRECOGNIZED_LINKBASE_LOCAL_DOCUMENTS_TYPE)
485
- self.currentReportData["localDocs"] = {
479
+ self.currentTargetReport["localDocs"] = {
486
480
  localDoc: sorted(docTypes)
487
481
  for localDoc, docTypes in localDocs.items()
488
482
  }
489
483
 
490
- if docSetFiles is not None:
491
- self.currentSourceReportData["docSetFiles"] = list(urllib.parse.quote(f) for f in docSetFiles)
492
-
493
484
  self.taxonomyData["prefixes"] = self.nsmap.prefixmap
494
485
  self.taxonomyData["roles"] = self.roleMap.prefixmap
495
486
 
@@ -504,7 +495,7 @@ class IXBRLViewerBuilder:
504
495
  iv.addFilingDoc(filingDocZipPath)
505
496
  self.taxonomyData["filingDocuments"] = filingDocZipName
506
497
 
507
- if not self.addViewerToXMLDocument(xmlDocument, scriptUrl):
498
+ if not self.addViewerData(iv.files[0], scriptUrl):
508
499
  return None
509
500
 
510
501
  return iv
@@ -524,9 +515,13 @@ class iXBRLViewer:
524
515
  self.filingDocuments = None
525
516
  # This is an arbitrary ModelXbrl used for logging only
526
517
  self.logger_model = logger_model
518
+ self.filenames = set()
527
519
 
528
520
  def addFile(self, ivf):
521
+ if ivf.filename in self.filenames:
522
+ return
529
523
  self.files.append(ivf)
524
+ self.filenames.add(ivf.filename)
530
525
 
531
526
  def addFilingDoc(self, filingDocuments):
532
527
  self.filingDocuments = filingDocuments