arelle-release 2.37.47__py3-none-any.whl → 2.37.49__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.

Files changed (100) hide show
  1. arelle/CntlrCmdLine.py +5 -1
  2. arelle/ModelObjectFactory.py +18 -2
  3. arelle/_version.py +2 -2
  4. arelle/plugin/validate/EDINET/Constants.py +6 -0
  5. arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +134 -7
  6. arelle/plugin/validate/EDINET/Statement.py +139 -0
  7. arelle/plugin/validate/EDINET/rules/contexts.py +5 -10
  8. arelle/plugin/validate/EDINET/rules/edinet.py +89 -51
  9. arelle/plugin/validate/EDINET/rules/gfm.py +41 -0
  10. {arelle_release-2.37.47.dist-info → arelle_release-2.37.49.dist-info}/METADATA +3 -1
  11. {arelle_release-2.37.47.dist-info → arelle_release-2.37.49.dist-info}/RECORD +15 -99
  12. arelle/archive/CustomLogger.py +0 -43
  13. arelle/archive/LoadEFMvalidate.py +0 -32
  14. arelle/archive/LoadSavePreLbCsv.py +0 -26
  15. arelle/archive/LoadValidate.cs +0 -31
  16. arelle/archive/LoadValidate.py +0 -36
  17. arelle/archive/LoadValidateCmdLine.java +0 -69
  18. arelle/archive/LoadValidatePostedZip.java +0 -57
  19. arelle/archive/LoadValidateWebService.java +0 -34
  20. arelle/archive/SaveTableToExelle.py +0 -140
  21. arelle/archive/TR3toTR4.py +0 -88
  22. arelle/archive/plugin/ESEF_2022/__init__.py +0 -47
  23. arelle/archive/plugin/bigInstance.py +0 -394
  24. arelle/archive/plugin/cmdWebServerExtension.py +0 -43
  25. arelle/archive/plugin/crashTest.py +0 -38
  26. arelle/archive/plugin/functionsXmlCreation.py +0 -106
  27. arelle/archive/plugin/hello_i18n.pot +0 -26
  28. arelle/archive/plugin/hello_i18n.py +0 -32
  29. arelle/archive/plugin/importTestChild1.py +0 -21
  30. arelle/archive/plugin/importTestChild2.py +0 -22
  31. arelle/archive/plugin/importTestGrandchild1.py +0 -21
  32. arelle/archive/plugin/importTestGrandchild2.py +0 -21
  33. arelle/archive/plugin/importTestImported1.py +0 -23
  34. arelle/archive/plugin/importTestImported11.py +0 -22
  35. arelle/archive/plugin/importTestParent.py +0 -48
  36. arelle/archive/plugin/instanceInfo.py +0 -306
  37. arelle/archive/plugin/loadFromOIM-2018.py +0 -1282
  38. arelle/archive/plugin/locale/fr/LC_MESSAGES/hello_i18n.po +0 -25
  39. arelle/archive/plugin/objectmaker.py +0 -285
  40. arelle/archive/plugin/packagedImportTest/__init__.py +0 -47
  41. arelle/archive/plugin/packagedImportTest/importTestChild1.py +0 -21
  42. arelle/archive/plugin/packagedImportTest/importTestChild2.py +0 -22
  43. arelle/archive/plugin/packagedImportTest/importTestGrandchild1.py +0 -21
  44. arelle/archive/plugin/packagedImportTest/importTestGrandchild2.py +0 -21
  45. arelle/archive/plugin/packagedImportTest/importTestImported1.py +0 -24
  46. arelle/archive/plugin/packagedImportTest/importTestImported11.py +0 -21
  47. arelle/archive/plugin/packagedImportTest/subdir/importTestImported111.py +0 -21
  48. arelle/archive/plugin/packagedImportTest/subdir/subsubdir/importTestImported1111.py +0 -21
  49. arelle/archive/plugin/sakaCalendar.py +0 -215
  50. arelle/archive/plugin/saveInstanceInfoset.py +0 -121
  51. arelle/archive/plugin/sphinx/FormulaGenerator.py +0 -823
  52. arelle/archive/plugin/sphinx/SphinxContext.py +0 -404
  53. arelle/archive/plugin/sphinx/SphinxEvaluator.py +0 -783
  54. arelle/archive/plugin/sphinx/SphinxMethods.py +0 -1287
  55. arelle/archive/plugin/sphinx/SphinxParser.py +0 -1093
  56. arelle/archive/plugin/sphinx/SphinxValidator.py +0 -163
  57. arelle/archive/plugin/sphinx/US-GAAP Ratios Example.xsr +0 -52
  58. arelle/archive/plugin/sphinx/__init__.py +0 -285
  59. arelle/archive/plugin/streamingExtensions.py +0 -335
  60. arelle/archive/plugin/updateTableLB.py +0 -242
  61. arelle/archive/plugin/validate/SBRnl/CustomLoader.py +0 -19
  62. arelle/archive/plugin/validate/SBRnl/DTS.py +0 -305
  63. arelle/archive/plugin/validate/SBRnl/Dimensions.py +0 -357
  64. arelle/archive/plugin/validate/SBRnl/Document.py +0 -799
  65. arelle/archive/plugin/validate/SBRnl/Filing.py +0 -467
  66. arelle/archive/plugin/validate/SBRnl/__init__.py +0 -75
  67. arelle/archive/plugin/validate/SBRnl/config.xml +0 -26
  68. arelle/archive/plugin/validate/SBRnl/sbr-nl-taxonomies.xml +0 -754
  69. arelle/archive/plugin/validate/USBestPractices.py +0 -570
  70. arelle/archive/plugin/validate/USCorpAction.py +0 -557
  71. arelle/archive/plugin/validate/USSecTagging.py +0 -337
  72. arelle/archive/plugin/validate/XDC/__init__.py +0 -77
  73. arelle/archive/plugin/validate/XDC/config.xml +0 -20
  74. arelle/archive/plugin/validate/XFsyntax/__init__.py +0 -64
  75. arelle/archive/plugin/validate/XFsyntax/xf.py +0 -2227
  76. arelle/archive/plugin/validate/calc2.py +0 -536
  77. arelle/archive/plugin/validateSchemaLxml.py +0 -156
  78. arelle/archive/plugin/validateTableInfoset.py +0 -52
  79. arelle/archive/us-gaap-dei-docType-extraction-frm.xml +0 -90
  80. arelle/archive/us-gaap-dei-ratio-cash-frm.xml +0 -150
  81. arelle/examples/plugin/formulaSuiteConverter.py +0 -212
  82. arelle/examples/plugin/functionsCustom.py +0 -59
  83. arelle/examples/plugin/hello_dolly.py +0 -64
  84. arelle/examples/plugin/multi.py +0 -58
  85. arelle/examples/plugin/rssSaveOim.py +0 -96
  86. arelle/examples/plugin/validate/XYZ/DisclosureSystems.py +0 -2
  87. arelle/examples/plugin/validate/XYZ/PluginValidationDataExtension.py +0 -10
  88. arelle/examples/plugin/validate/XYZ/ValidationPluginExtension.py +0 -50
  89. arelle/examples/plugin/validate/XYZ/__init__.py +0 -75
  90. arelle/examples/plugin/validate/XYZ/resources/config.xml +0 -16
  91. arelle/examples/plugin/validate/XYZ/rules/__init__.py +0 -0
  92. arelle/examples/plugin/validate/XYZ/rules/rules01.py +0 -110
  93. arelle/examples/plugin/validate/XYZ/rules/rules02.py +0 -59
  94. arelle/scripts-macOS/startWebServer.command +0 -3
  95. arelle/scripts-unix/startWebServer.sh +0 -1
  96. arelle/scripts-windows/startWebServer.bat +0 -5
  97. {arelle_release-2.37.47.dist-info → arelle_release-2.37.49.dist-info}/WHEEL +0 -0
  98. {arelle_release-2.37.47.dist-info → arelle_release-2.37.49.dist-info}/entry_points.txt +0 -0
  99. {arelle_release-2.37.47.dist-info → arelle_release-2.37.49.dist-info}/licenses/LICENSE.md +0 -0
  100. {arelle_release-2.37.47.dist-info → arelle_release-2.37.49.dist-info}/top_level.txt +0 -0
@@ -1,140 +0,0 @@
1
- '''
2
- This module is an example to convert Html Tables into Xlsx (Excel) tables
3
- Preconfigured here to use SEC Edgar Rendering R files as input
4
-
5
- See COPYRIGHT.md for copyright information.
6
- '''
7
- import os, sys
8
- import regex as re
9
- from lxml import etree, html
10
- from openpyxl.workbook import Workbook
11
- from openpyxl.worksheet import ColumnDimension
12
- from openpyxl.cell import get_column_letter
13
- from openpyxl.style import Alignment
14
-
15
- class Report():
16
- def __init__(self, longName, shortName, htmlFileName):
17
- self.longName = longName
18
- self.shortName = shortName
19
- self.htmlFileName = htmlFileName
20
- def __repr__(self):
21
- return ("report(longName='{}', shortName='{}', htmlFileName='{}')"
22
- .format(self.longName, self.shortName, self.htmlFileName))
23
-
24
- def intCol(elt, attrName, default=None):
25
- try:
26
- return int(elt.get(attrName, default))
27
- except (TypeError, ValueError):
28
- return default
29
-
30
- numberPattern = re.compile(r"\s*([$]\s*)?[(]?\s*[+-]?[0-9,]+([.][0-9]*)?[)-]?\s*$")
31
- displayNonePattern = re.compile(r"\s*display:\s*none;")
32
-
33
- def saveTableToExelle(rFilesDir):
34
-
35
- # get reports from FilingSummary
36
- reports = []
37
- try:
38
- fsdoc = etree.parse(os.path.join(rFilesDir, "FilingSummary.xml"))
39
- for rElt in fsdoc.iter(tag="Report"):
40
- reports.append(Report(rElt.findtext("LongName"),
41
- rElt.findtext("ShortName"),
42
- rElt.findtext("HtmlFileName")))
43
- except (EnvironmentError,
44
- etree.LxmlError) as err:
45
- print("FilingSummary.xml: directory {0} error: {1}".format(rFilesDir, err))
46
-
47
- wb = Workbook(encoding='utf-8')
48
- # remove predefined sheets
49
- for sheetName in wb.get_sheet_names():
50
- ws = wb.get_sheet_by_name(sheetName)
51
- if ws is not None:
52
- wb.remove_sheet(ws)
53
-
54
- sheetNames = set() # prevent duplicates
55
-
56
- for reportNum, report in enumerate(reports):
57
- sheetName = report.shortName[:31] # max length 31 for excel title
58
- if sheetName in sheetNames:
59
- sheetName = sheetName[:31-len(str(reportNum))] + str(reportNum)
60
- sheetNames.add(sheetName)
61
- ws = wb.create_sheet(title=sheetName)
62
-
63
- try:
64
- # doesn't detect utf-8 encoding the normal way, pass it a string
65
- #htmlSource = ''
66
- #with open(os.path.join(rFilesDir, report.htmlFileName), 'rt', encoding='utf-8') as fh:
67
- # htmlSource = fh.read()
68
- #rdoc = html.document_fromstring(htmlSource)
69
- rdoc = html.parse(os.path.join(rFilesDir, report.htmlFileName))
70
- row = -1
71
- mergedAreas = {} # colNumber: (colspan,lastrow)
72
- for tableElt in rdoc.iter(tag="table"):
73
- # skip pop up tables
74
- if tableElt.get("class") == "authRefData":
75
- continue
76
- if tableElt.getparent().tag == "div":
77
- style = tableElt.getparent().get("style")
78
- if style and displayNonePattern.match(style):
79
- continue
80
- colWidths = {}
81
- for rowNum, trElt in enumerate(tableElt.iter(tag="tr")):
82
- # remove passed mergedAreas
83
- for mergeCol in [col
84
- for col, mergedArea in mergedAreas.items()
85
- if mergedArea[1] > rowNum]:
86
- del mergedAreas[mergeCol]
87
- col = 0
88
- for coltag in ("th", "td"):
89
- for cellElt in trElt.iter(tag=coltag):
90
- if col == 0:
91
- row += 1 # new row
92
- if col in mergedAreas:
93
- col += mergedAreas[col][0] - 1
94
- text = cellElt.text_content()
95
- colspan = intCol(cellElt, "colspan", 1)
96
- rowspan = intCol(cellElt, "rowspan", 1)
97
- #if col not in colWidths:
98
- # colWidths[col] = 10.0 # some kind of default width
99
- for elt in cellElt.iter():
100
- style = elt.get("style")
101
- if style and "width:" in style:
102
- try:
103
- kw, sep, width = style.partition("width:")
104
- if "px" in width:
105
- width, sep, kw = width.partition("px")
106
- width = float(width) * 0.67777777
107
- else:
108
- width = float(width)
109
- colWidths[col] = width
110
- except ValueError:
111
- pass
112
- if rowspan > 1:
113
- mergedAreas[col] = (colspan, row + rowspan - 1)
114
- cell = ws.cell(row=row,column=col)
115
- if text:
116
- cell.value = text
117
- if numberPattern.match(text):
118
- cell.style.alignment.horizontal = Alignment.HORIZONTAL_RIGHT
119
- else:
120
- cell.style.alignment.wrap_text = True
121
- if colspan > 1 or rowspan > 1:
122
- ws.merge_cells(start_row=row, end_row=row+rowspan-1, start_column=col, end_column=col+colspan-1)
123
- cell.style.alignment.vertical = Alignment.VERTICAL_TOP
124
- if coltag == "th":
125
- cell.style.alignment.horizontal = Alignment.HORIZONTAL_CENTER
126
- cell.style.font.bold = True
127
- cell.style.font.size = 9 # some kind of default size
128
- col += colspan
129
- for col, width in colWidths.items():
130
- ws.column_dimensions[get_column_letter(col+1)].width = width
131
- except (EnvironmentError,
132
- etree.LxmlError) as err:
133
- print("{0}: directory {1} error: {2}".format(report.htmlFileName, rFilesDir, err))
134
-
135
- wb.save(os.path.join(rFilesDir, "exelleOut.xlsx"))
136
-
137
- if __name__ == "__main__":
138
-
139
- # test directory
140
- saveTableToExelle(r"C:\Users\Herm Fischer\Documents\mvsl\projects\SEC\14.1\R-files\wpoRfiles")
@@ -1,88 +0,0 @@
1
- '''
2
- See COPYRIGHT.md for copyright information.
3
- License: https://www.apache.org/licenses/LICENSE-2.0
4
-
5
- usage: python3 {tr2 or tr3 input-file} {tr4 output-file}
6
- '''
7
-
8
- import io, os, sys, time
9
- from lxml import etree
10
-
11
- if len(sys.argv) < 3:
12
- print("Please enter input and output filename arguments")
13
- exit(1)
14
- INFILE = sys.argv[1]
15
- OUTFILE = sys.argv[2]
16
-
17
- if not INFILE or not os.path.isfile(INFILE) or not OUTFILE:
18
- print("Please enter existing input filename and output filename")
19
- exit(1)
20
-
21
- xhtmlNs = "http://www.w3.org/1999/xhtml"
22
- ixNS = "http://www.xbrl.org/2013/inlineXBRL"
23
- ixEltsWithFormat = ["{{{}}}{}".format(ixNS, localName) for localName in ("denominator", "numerator", "nonFraction", "nonNumeric")]
24
- xhtmlRootElts = ["{{{}}}{}".format(xhtmlNs, localName) for localName in ("html", "xhtml")]
25
- TR2NS = "http://www.xbrl.org/inlineXBRL/transformation/2011-07-31"
26
- TR3NS = "http://www.xbrl.org/inlineXBRL/transformation/2015-02-26"
27
- TR4NS = "http://www.xbrl.org/inlineXBRL/transformation/2020-02-12"
28
- TR23to4 = {
29
- "booleanfalse": "fixed-false",
30
- "booleantrue": "fixed-true",
31
- "calindaymonthyear": "date-ind-day-monthname-year-hi",
32
- "datedaymonth": "date-day-month",
33
- "datedaymonthdk": "date-day-monthname-da",
34
- "datedaymonthen": "date-day-monthname-en",
35
- "datedaymonthyear": "date-day-month-year",
36
- "datedaymonthyeardk": "date-day-monthname-year-da",
37
- "datedaymonthyearen": "date-day-monthname-year-en",
38
- "datedaymonthyearin": "date-day-monthname-year-hi", # does not handle this: Use date-day-month-year when using Devanagari numerals for the month, otherwise use date-day-monthname-year-hi.
39
- "dateerayearmonthdayjp": "date-jpn-era-year-month-day",
40
- "dateerayearmonthjp": "date-jpn-era-year-month",
41
- "datemonthday": "date-month-day",
42
- "datemonthdayen": "date-monthname-day-en",
43
- "datemonthdayyear": "date-month-day-year",
44
- "datemonthdayyearen": "date-monthname-day-year-en",
45
- "datemonthyear": "date-month-year",
46
- "datemonthyeardk": "date-monthname-year-da",
47
- "datemonthyearen": "date-monthname-year-en",
48
- "datemonthyearin": "date-monthname-year-hi",
49
- "dateyearmonthday": "date-year-month-day",
50
- "dateyearmonthdaycjk": "date-year-month-day",
51
- "dateyearmonthcjk": "date-year-month",
52
- "dateyearmonthen": "date-year-monthname-en",
53
- "nocontent": "fixed-empty",
54
- "numcommadecimal": "num-comma-decimal",
55
- "numdotdecimal": "num-dot-decimal",
56
- "numdotdecimalin": "num-dot-decimal",
57
- "numunitdecimal": "num-unit-decimal",
58
- "numunitdecimalin": "num-unit-decimal",
59
- "zerodash": "fixed-zero"
60
- }
61
-
62
- print("Parsing TR3 file {}".format(INFILE))
63
- startedAt = time.time()
64
- parser = etree.XMLParser(recover=True, huge_tree=True)
65
- with io.open(INFILE, "rb") as fh:
66
- doc = etree.parse(fh,parser=parser,base_url=INFILE)
67
-
68
- # replace format TR3 with TR4
69
- nsToChange = set()
70
- for elt in doc.iter(*ixEltsWithFormat):
71
- prefix, _sep, localName = elt.get("format", "").rpartition(":")
72
- if localName:
73
- ns = elt.nsmap.get(prefix)
74
- if ns in (TR2NS, TR3NS):
75
- if localName in TR23to4:
76
- elt.set("format", "ixt:" + TR23to4[localName])
77
- nsToChange.add(ns)
78
- else:
79
- print("{} line {}: nable to convert transform {}".format(elt.tag, elt.sourceline, elt.get("format")))
80
-
81
- # replace TR2 and TR3 namespaces in any xmlns'ed element
82
- outXhtml = etree.tostring(doc, encoding=doc.docinfo.encoding, xml_declaration=True)
83
- for ns in nsToChange:
84
- outXhtml = outXhtml.replace(ns.encode(), TR4NS.encode())
85
-
86
- with io.open(OUTFILE, "wb", ) as fh:
87
- fh.write(outXhtml)
88
- print("Converted in {:.3f} secs, TR4 file {}".format(time.time()-startedAt, INFILE))
@@ -1,47 +0,0 @@
1
- """
2
- See COPYRIGHT.md for copyright information.
3
- """
4
- from __future__ import annotations
5
-
6
- from typing import Any
7
-
8
- from arelle.ModelDocument import LoadingException, ModelDocument
9
- from arelle.ModelXbrl import ModelXbrl
10
- from arelle.Version import authorLabel, copyrightLabel
11
- from arelle.typing import TypeGetText
12
- from arelle.utils.PluginHooks import PluginHooks
13
-
14
- _: TypeGetText
15
-
16
-
17
- class DeprecatedESEF2022Plugin(PluginHooks):
18
- """
19
- The 'validate/ESEF_2022' plugin has been merged into the `validate/ESEF` plugin using disclosure systems to select the year.
20
- This implementation only exists to raise an error and inform users to migrate their configuration.
21
- """
22
-
23
- @staticmethod
24
- def modelDocumentPullLoader(
25
- modelXbrl: ModelXbrl,
26
- normalizedUri: str,
27
- filepath: str,
28
- isEntry: bool,
29
- namespace: str | None,
30
- *args: Any,
31
- **kwargs: Any,
32
- ) -> ModelDocument | LoadingException | None:
33
- message = _("The 'validate/ESEF_2022' plugin has been combined with the 'validate/ESEF' plugin. Please use the 'validate/ESEF' plugin with a 2022 disclosure system.")
34
- modelXbrl.error("plugin:deprecated", message)
35
- return LoadingException(message)
36
-
37
-
38
- __pluginInfo__ = {
39
- "name": "Validate ESMA ESEF-2022",
40
- "version": "1.2023.00",
41
- "description": "Deprecated: use the 'validate/ESEF' plugin with a 2022 disclosure system instead.",
42
- "license": "Apache-2",
43
- "author": authorLabel,
44
- "copyright": copyrightLabel,
45
- "import": ("inlineXbrlDocumentSet",),
46
- "ModelDocument.PullLoader": DeprecatedESEF2022Plugin.modelDocumentPullLoader,
47
- }
@@ -1,394 +0,0 @@
1
- '''
2
- BigInstance is an example of a plug-in to both GUI menu and command line/web service
3
- that provides an alternative approach to big instance documents without building a DOM, to save
4
- memory footprint. SAX is used to parse the big instance. ModelObjects are specialized by features
5
- for efficiency and to avoid dependency on an underlying DOM.
6
-
7
- See COPYRIGHT.md for copyright information.
8
- '''
9
-
10
- import xml.sax, io, sys
11
- from collections import defaultdict
12
- from arelle import XbrlConst, XmlUtil, XmlValidate
13
- from arelle.ModelDocument import ModelDocument, Type
14
- from arelle.ModelObject import ModelObject
15
- from arelle.ModelValue import QName
16
- from arelle.ModelInstanceObject import ModelContext, ModelFact, ModelUnit
17
- from arelle.Version import authorLabel, copyrightLabel
18
-
19
- class NotInstanceDocumentException(Exception):
20
- def __init__(self):
21
- pass
22
-
23
- sharedEmptyDict = {}
24
- sharedEmptyList = []
25
-
26
- qnIDattr = QName(None, None, "id")
27
- qnContextRefAttr = QName(None, None, "contextRef")
28
- qnUnitRefAttr = QName(None, None, "unitRef")
29
- qnPrecisionAttr = QName(None, None, "precision")
30
- qnDecimalsAttr = QName(None, None, "decimals")
31
-
32
- def initModelObject(obj, saxhandler, qname, attrs):
33
- obj._elementQname = qname
34
- obj._namespaceURI = qname.namespaceURI
35
- obj._localName = qname.localName
36
- obj.modelDocument = saxhandler.modelDocument
37
- obj._sourceline = saxhandler.saxParser.getLineNumber()
38
- obj._parent = saxhandler.qnameStack[0] if saxhandler.qnameStack else None
39
- obj._attrs = dict((('{{{0}}}{1}'.format(*name) if name[0] else name[1]), value)
40
- for name, value in attrs.items())
41
- obj._elementText = ''
42
-
43
- class BigInstModelObject(ModelObject):
44
- def __init__(self, saxhandler, qname, attrs):
45
- initModelObject(self, saxhandler, qname, attrs)
46
- super(BigInstModelObject, self).init(saxhandler.modelDocument)
47
-
48
- def getparent(self):
49
- return self._parent
50
-
51
- def items(self):
52
- return self._attrs.items()
53
-
54
- def get(self, clarkName):
55
- return self._attrs.get(clarkName)
56
-
57
- @property
58
- def sourceline(self):
59
- return self._sourceline
60
-
61
- @property
62
- def elementText(self):
63
- return self._elementText
64
-
65
- class BigInstContext(ModelContext):
66
- def __init__(self, saxhandler, qname, attrs):
67
- initModelObject(self, saxhandler, qname, attrs)
68
- super(BigInstContext, self).init(saxhandler.modelDocument)
69
- self._isStartEndPeriod = self._isInstantPeriod = self._isForeverPeriod = False
70
-
71
- def getparent(self):
72
- return self._parent
73
-
74
- def items(self):
75
- return self._attrs.items()
76
-
77
- def get(self, clarkName):
78
- return self._attrs.get(clarkName)
79
-
80
- @property
81
- def sourceline(self):
82
- return self._sourceline
83
-
84
- @property
85
- def elementText(self):
86
- return self._elementText
87
-
88
- class BigInstUnit(ModelUnit):
89
- def __init__(self, saxhandler, qname, attrs):
90
- initModelObject(self, saxhandler, qname, attrs)
91
- super(BigInstUnit, self).init(saxhandler.modelDocument)
92
- self._measures = [[],[]]
93
-
94
- def getparent(self):
95
- return self._parent
96
-
97
- def items(self):
98
- return self._attrs.items()
99
-
100
- def get(self, clarkName):
101
- return self._attrs.get(clarkName)
102
-
103
- @property
104
- def sourceline(self):
105
- return self._sourceline
106
-
107
- @property
108
- def elementText(self):
109
- return self._elementText
110
-
111
- class BigInstFact(ModelFact):
112
- __slots__ = ("_parent", "_concept", "_attrs", "_sourceline", "_elementText",
113
- "_context", "_conceptContextUnitLangHash",
114
- "_isItem", "_isTuple", "_isNumeric", "_isFraction",
115
- "_id", "_decimals", "_precision",
116
- "modelDocument", "objectIndex", "modelTupleFacts",
117
- "_parentBigInstObj", "_prevObj", "_nextObj",
118
- "xValid", "xValue", "sValue", "xAttributes")
119
-
120
- # reimplement ancestorQnames, parentQname
121
-
122
- def __init__(self, saxhandler, qname, attrs):
123
- self._concept = saxhandler.modelXbrl.qnameConcepts.get(qname) # use the qname object of the DTS, not parser
124
- self.modelDocument = saxhandler.modelDocument
125
- self._sourceline = saxhandler.saxParser.getLineNumber()
126
- self._parent = saxhandler.qnameStack[0] if saxhandler.qnameStack else None
127
- self._context = self._unit = self._decimals = self._precision = self._id = None
128
- self.xValid = 0 # unvalidated
129
- self._attrs = sharedEmptyDict # try with common shared emptyDict if no separate attributes
130
- self._parentBigInstObj = self._prevObj = self._nextObj = 1234
131
- for names, value in attrs.items():
132
- attrNameURI, attrLocalName= names
133
- if not attrNameURI:
134
- if attrLocalName == "id":
135
- self._id = value
136
- elif attrLocalName == "decimals":
137
- self._decimals = value
138
- elif attrLocalName == "precision":
139
- self._precision = value
140
- elif attrLocalName == "contextRef":
141
- self._context = saxhandler.modelXbrl.contexts.get(value, 0)
142
- if self._context == 0: # provide dummmy non-none so attribute is present for validation
143
- saxhandler.contextRefedFacts[value].append(self)
144
- elif attrLocalName == "unitRef":
145
- self._unit = saxhandler.modelXbrl.units.get(value, 0)
146
- if self._unit == 0:
147
- saxhandler.unitRefedFacts[value].append(self)
148
- else:
149
- if not self._attrs: self.attrs = {} # stop using common shared emptyDict
150
- self._attrs[attrLocalName] = value
151
- else:
152
- if not self._attrs: self.attrs = {} # stop using common shared emptyDict
153
- self._attrs['{{{0}}}{1}'.format(attrNameURI, attrLocalName)] = value
154
- self._elementText = ''
155
- self.modelTupleFacts = sharedEmptyList
156
- super(ModelFact, self).init(saxhandler.modelDocument)
157
-
158
- def getparent(self):
159
- return self._parent
160
-
161
- def items(self):
162
- return self._attrs.items()
163
-
164
- def get(self, clarkName):
165
- return self._attrs.get(clarkName)
166
-
167
- @property
168
- def sourceline(self):
169
- return self._sourceline
170
-
171
- @property
172
- def concept(self):
173
- return self._concept
174
-
175
- @property
176
- def qname(self):
177
- return self._concept.qname
178
-
179
- @property
180
- def elementQname(self):
181
- return self._concept.qname
182
-
183
- @property
184
- def namespaceURI(self):
185
- return self._concept.qname.namespaceURI
186
-
187
- @property
188
- def localName(self):
189
- return self._concept.qname.localName
190
-
191
- @property
192
- def elementText(self):
193
- return self._elementText
194
-
195
- @property
196
- def contextID(self):
197
- if self._context is not None:
198
- return self._context.id
199
- return None
200
-
201
- @property
202
- def slottedAttributesNames(self):
203
- names = set()
204
- if self._id: names.add(qnIDattr)
205
- if self._context is not None: names.add(qnContextRefAttr)
206
- if self._unit is not None: names.add(qnUnitRefAttr)
207
- if self._decimals is not None: names.add(qnDecimalsAttr)
208
- if self._precision is not None: names.add(qnPrecisionAttr)
209
- return names
210
-
211
- @property
212
- def unitID(self):
213
- if self._unit is not None:
214
- return self._unit.id
215
- return None
216
-
217
- class saxHandler(xml.sax.ContentHandler):
218
- def __init__(self, saxParser, modelXbrl, mappedUri, filepath):
219
- self.saxParser = saxParser
220
- self.modelXbrl = modelXbrl
221
- self.mappedUri = mappedUri
222
- self.filepath = filepath
223
- self.nsmap = {}
224
- self.prefixmap = {}
225
- self.qnameStack = []
226
- self.currentNamespaceURI = None
227
- self.modelDocument = None
228
- self.contextRefedFacts = defaultdict(list)
229
- self.unitRefedFacts = defaultdict(list)
230
-
231
- def qname(self, prefixedName):
232
- prefix, sep, localName = prefixedName.rpartition(":")
233
- return QName(prefix, self.nsmap.get(prefix,None), localName)
234
-
235
- def startPrefixMapping(self, prefix, uri):
236
- self.nsmap[prefix] = uri
237
- self.prefixmap[uri] = prefix
238
-
239
- def endPrefixMapping(self, prefix):
240
- if prefix in self.nsmap:
241
- self.prefixmap.pop(self.nsmap[prefix], None)
242
- self.nsmap.pop(prefix, None)
243
-
244
- def startElementNS(self, name, qname, attrs):
245
- namespaceURI, localName = name
246
- prefix = self.prefixmap.get(namespaceURI, None)
247
- thisQname = QName(prefix, namespaceURI, localName)
248
- if not self.qnameStack:
249
- if thisQname != XbrlConst.qnXbrliXbrl: # not an instance document
250
- self.modelXbrl = None # dereference
251
- self.saxParser = None
252
- raise NotInstanceDocumentException()
253
- if self.modelDocument is None:
254
- self.modelDocument = ModelDocument(self.modelXbrl, Type.INSTANCE, self.mappedUri, self.filepath, None)
255
- parentQname = None
256
- elif self.qnameStack:
257
- parentElement = self.qnameStack[0]
258
- parentQname = parentElement.elementQname
259
- if namespaceURI in (XbrlConst.xbrli, XbrlConst.link):
260
- if parentQname == XbrlConst.qnXbrliContext:
261
- if localName == "identifier":
262
- parentElement._entityIdentifier = (attrs.get(None,"scheme"), "")
263
- elif localName == "forever":
264
- parentElement._isForeverPeriod = True
265
- else:
266
- if localName == "context":
267
- thisModelObject = BigInstContext(self, thisQname, attrs)
268
- self.modelXbrl.contexts[thisModelObject.id] = thisModelObject
269
- elif localName == "unit":
270
- thisModelObject = BigInstUnit(self, thisQname, attrs)
271
- self.modelXbrl.units[thisModelObject.id] = thisModelObject
272
- else:
273
- thisModelObject = BigInstModelObject(self, thisQname, attrs)
274
- if localName in ("schemaRef", "linkbaseRef"):
275
- self.modelDocument.discoverHref(thisModelObject)
276
- else:
277
- self.qnameStack.insert(0, thisModelObject)
278
- elif parentQname:
279
- if parentQname == XbrlConst.qnXbrliContext:
280
- if namespaceURI == XbrlConst.xbrldi:
281
- if localName == "explicitMember":
282
- self.dimensionPrefixedName = attrs.get(None,"dimension")
283
- else: # might be a fact
284
- thisModelObject = BigInstFact(self, thisQname, attrs)
285
- if len(self.qnameStack) > 1:
286
- tuple = self.qnameStack[0]
287
- if not tuple.modelTupleFacts:
288
- tuple.modelTupleFacts = [] # allocate unshared list
289
- tuple.modelTupleFacts.append(thisModelObject)
290
- else:
291
- self.modelXbrl.facts.append(thisModelObject)
292
- self.qnameStack.insert(0, thisModelObject) # build content
293
- self.currentNamespaceURI = namespaceURI
294
- self.currentLocalName = localName
295
-
296
- def endElementNS(self, name, qname):
297
- thisQname = QName(None, *name)
298
- if self.qnameStack and self.qnameStack[0].elementQname == thisQname:
299
- elt = self.qnameStack.pop(0)
300
- if elt.namespaceURI == XbrlConst.xbrli:
301
- if elt.localName == "unit":
302
- elt._measures = (sorted(elt._measures[0]), sorted(elt._measures[1]))
303
- if elt.id in self.unitRefedFacts:
304
- for fact in self.unitRefedFacts[elt.id]:
305
- fact._unit = elt
306
- del self.unitRefedFacts[elt.id]
307
- elif elt.localName == "context":
308
- if elt.id in self.contextRefedFacts:
309
- for fact in self.contextRefedFacts[elt.id]:
310
- fact._context = elt
311
- del self.contextRefedFacts[elt.id]
312
- self.currentNamespaceURI = None
313
- self.currentLocalName = None
314
- XmlValidate.validate(self.modelXbrl, elt, recurse=False)
315
- pass
316
-
317
- def characters(self, content):
318
- if self.currentNamespaceURI:
319
- elt = self.qnameStack[0]
320
- if self.currentNamespaceURI == XbrlConst.xbrli:
321
- s = content.strip()
322
- if s:
323
- if self.currentLocalName == "identifier":
324
- elt._entityIdentifier = (elt._entityIdentifier[0], elt._entityIdentifier[1] + content)
325
- elif self.currentLocalName == "startDate":
326
- elt._startDatetime = XmlUtil.datetimeValue(s)
327
- elt._isStartEndPeriod = True
328
- elif self.currentLocalName == "endDate":
329
- elt._endDatetime = XmlUtil.datetimeValue(s, addOneDay=True)
330
- elt._isStartEndPeriod = True
331
- elif self.currentLocalName == "instant":
332
- elt._endDatetime = elt._instantDatetime = XmlUtil.datetimeValue(s, addOneDay=True)
333
- elt._isInstantPeriod = True
334
- elif self.currentLocalName == "measure":
335
- m = self.qname(content)
336
- parentEltLocalName = self.qnameStack[1].localName
337
- if parentEltLocalName == "unit":
338
- self.qnameStack[1]._measures[0].append(m)
339
- elif parentEltLocalName == "unitNumerator" and self.qnameStack[2].localName == "unit":
340
- self.qnameStack[2]._measures[0].append(m)
341
- elif parentEltLocalName == "unitDenominator" and self.qnameStack[2].localName == "unit":
342
- self.qnameStack[2]._measures[1].append(m)
343
- elif self.currentNamespaceURI == XbrlConst.xbrldi:
344
- s = content.strip()
345
- if s:
346
- if self.currentLocalName == "explicitMember" and self.dimensionPrefixedName:
347
- dimQname = self.qname(self.currentLocalName)
348
- memQname = self.qname(s)
349
- dimConcept = self.modelXbrl.qnameConcepts.get(dimQname)
350
- memConcept = self.modelXbrl.qnameConcepts.get(memQname)
351
- elif elt is not None:
352
- elt._elementText += content
353
-
354
- def skippedEntity(self, name):
355
- print ("skipped entity={0}".format(name))
356
-
357
- class BigInstDocument:
358
- def __init__(self, file, xbrlParser, saxParser, saxHandler):
359
- self.file = file
360
- self.xbrlParser = xbrlParser
361
- self.saxParser = saxParser
362
- self.saxHandler = saxHandler
363
-
364
- def getroot(self):
365
- return self.saxHandler.qnameStack[-1]
366
-
367
- def bigInstLoader(modelXbrl, file, mappedUri, filepath):
368
- saxParser = xml.sax.make_parser()
369
- saxParser.setFeature("http://xml.org/sax/features/namespaces", True)
370
- saxParser.setFeature("http://xml.org/sax/features/external-general-entities", True)
371
- saxhandler = saxHandler(saxParser, modelXbrl, mappedUri, filepath)
372
- saxParser.setContentHandler(saxhandler)
373
- try:
374
- saxParser.parse(file)
375
- return saxhandler.modelDocument
376
- except NotInstanceDocumentException:
377
- file.seek(0,io.SEEK_SET) # allow reparsing
378
- return None
379
-
380
- '''
381
- Do not use _( ) in pluginInfo itself (it is applied later, after loading
382
- '''
383
-
384
- __pluginInfo__ = {
385
- 'name': 'Big Instance Loader',
386
- 'version': '0.9',
387
- 'description': "This plug-in loads big XBRL instances without building a DOM in memory. "
388
- "SAX parses XBRL directly into an object model without a DOM. ",
389
- 'license': 'Apache-2',
390
- 'author': authorLabel,
391
- 'copyright': copyrightLabel,
392
- # classes of mount points (required)
393
- 'ModelDocument.CustomLoader': bigInstLoader,
394
- }