def dir(self): self.open() if not self.isOpen: return None elif self.filesDir is not None: return self.filesDir elif self.isZip: files = [] for zipinfo in self.fs.infolist(): files.append(zipinfo.filename) self.filesDir = files elif self.isTarGz: self.filesDir = self.fs.getnames() elif self.isEis: files = [] for docElt in self.eisDocument.iter(tag=u"{http://www.sec.gov/edgar/common}document"): outfn = docElt.findtext(u"{http://www.sec.gov/edgar/common}conformedName") if outfn: files.append(outfn); self.filesDir = files elif self.isXfd: files = [] for data in self.xfdDocument.iter(tag=u"data"): outfn = data.findtext(u"filename") if outfn: if len(outfn) > 2 and outfn[0].isalpha() and \ outfn[1] == u':' and outfn[2] == u'\\': continue files.append(outfn); self.filesDir = files elif self.isRss: files = [] # return title, descr, pubdate, linst doc edgr = u"http://www.sec.gov/Archives/edgar" try: for dsElt in XmlUtil.descendants(self.rssDocument, None, u"item"): instDoc = None for instDocElt in XmlUtil.descendants(dsElt, edgr, u"xbrlFile"): if instDocElt.get(u"(http://www.sec.gov/Archives/edgar}description").endswith(u"INSTANCE DOCUMENT"): instDoc = instDocElt.get(u"(http://www.sec.gov/Archives/edgar}url") break if not instDoc: continue files.append(( XmlUtil.text(XmlUtil.descendant(dsElt, None, u"title")), # tooltip u"{0}\n {1}\n {2}\n {3}\n {4}".format( XmlUtil.text(XmlUtil.descendant(dsElt, edgr, u"companyName")), XmlUtil.text(XmlUtil.descendant(dsElt, edgr, u"formType")), XmlUtil.text(XmlUtil.descendant(dsElt, edgr, u"filingDate")), XmlUtil.text(XmlUtil.descendant(dsElt, edgr, u"cikNumber")), XmlUtil.text(XmlUtil.descendant(dsElt, edgr, u"period"))), XmlUtil.text(XmlUtil.descendant(dsElt, None, u"description")), XmlUtil.text(XmlUtil.descendant(dsElt, None, u"pubDate")), instDoc)) self.filesDir = files except (EnvironmentError, etree.LxmlError), err: pass
def parent_child(args, parentName, descendantName): if len(args) != 1: raise XPathContext.FunctionNumArgs() if len(args[0]) != 1: raise XPathContext.FunctionArgType(1,"xbrl:" + parentName) parent = args[0][0] if isinstance(parent,ModelObject.ModelObject): parent = parent.element if isinstance(parent,xml.dom.Node) and parent.nodeType == 1 and \ parent.localName == parentName and parent.namespaceURI == XbrlConst.xbrli: if descendantName.startswith('@'): return parent.getAttribute(descendantName[1:]) elif descendantName == 'text()': return XmlUtil.text(parent) elif descendantName == 'strip-text()': return XmlUtil.text(parent).strip() else: return XmlUtil.child(parent, XbrlConst.xbrli, descendantName) raise XPathContext.FunctionArgType(1,"xbrl:" + parentName)
def expected(self): if self.localName == "testcase": return self.document.basename[:4] #starts with PASS or FAIL errorElement = XmlUtil.descendant(self, None, "error") if errorElement is not None: return ModelValue.qname(errorElement, XmlUtil.text(errorElement)) resultElement = XmlUtil.descendant(self, None, "result") if resultElement is not None: expected = resultElement.get("expected") if expected: return expected for assertElement in XmlUtil.children(resultElement, None, "assert"): num = assertElement.get("num") if len(num) == 5: return "EFM.{0}.{1}.{2}".format(num[0],num[1:3],num[3:6]) asserTests = {} for atElt in XmlUtil.children(resultElement, None, "assertionTests"): try: asserTests[atElt.get("assertionID")] = (_INT(atElt.get("countSatisfied")),_INT(atElt.get("countNotSatisfied"))) except ValueError: pass if asserTests: return asserTests elif self.get("result"): return self.get("result") return None
def explicitDims(self): return { (self.prefixedNameQname(e.get("dimension")), self.prefixedNameQname(XmlUtil.text(qn))) for e in XmlUtil.children(self, XbrlConst.formula, "explicitDimension") for m in XmlUtil.children(e, XbrlConst.formula, "member") for qn in XmlUtil.children(m, XbrlConst.formula, "qname") }
def vEqual(modelConcept1, node1, modelConcept2, node2): text1 = XmlUtil.text(node1) text2 = XmlUtil.text(node2) if modelConcept1: baseXsdType1 = modelConcept1.baseXsdType if len(text1) == 0 and modelConcept1.default is not None: text1 = modelConcept1.default else: baseXsdType1 = None if modelConcept2: baseXsdType2 = modelConcept2.baseXsdType if len(text2) == 0 and modelConcept2.default is not None: text1 = modelConcept2.default else: baseXsdType2 = None return xTypeValue(baseXsdType1, node1, node1, text1) == xTypeValue(baseXsdType2, node2, node2, text2)
def time(value, castException=None): if value == "MinTime": return Time(time.min) elif value == "MaxTime": return Time(time.max) elif isinstance(value, xml.dom.Node): if value.nodeType == xml.dom.Node.ELEMENT_NODE: from arelle import (XmlUtil) value = XmlUtil.text(value) elif value.nodeType == xml.dom.Node.ATTRIBUTE_NODE: value = value.value else: value = None elif isinstance(value, datetime.time): return Time(value.hour, value.minute, value.second, value.microsecond, value.tzinfo) elif isinstance(value, datetime.datetime): return Time(value.hour, value.minute, value.second, value.microsecond, value.tzinfo) elif castException and not isinstance(value, str): raise castException if value is None: return None match = timePattern.match(value.strip()) if match is None: return None return Time(int(match.group(1)),int(match.group(2)),int(match.group(3)))
def pubDate(self): try: return self._pubDate except AttributeError: from arelle.UrlUtil import parseRfcDatetime self._pubDate = parseRfcDatetime(XmlUtil.text(XmlUtil.descendant(self, None, "pubDate"))) return self._pubDate
def stepAxis(self, op, p, sourceSequence): targetSequence = [] for node in sourceSequence: if not isinstance(node,(ModelObject.ModelObject, xml.dom.Node)): raise XPathException(p, 'err:XPTY0020', _('Axis step {0} context item is not a node: {1}').format(op, node)) targetNodes = [] if isinstance(node, ModelObject.ModelObject): node = node.element if isinstance(p,QNameDef): ns = p.namespaceURI; localname = p.localName if p.isAttribute: if p.unprefixed: if node.hasAttribute(localname): targetNodes.append(node.getAttribute(localname)) else: if node.hasAttributeNS(ns,localname): targetNodes.append(node.getAttributeNS(ns,localname)) elif op == '/' or op is None: targetNodes = XmlUtil.children(node, ns, localname) elif op == '//': targetNodes = XmlUtil.descendants(node, ns, localname) elif op == '..': targetNodes = [ XmlUtil.parent(node) ] elif isinstance(p, OperationDef) and isinstance(p.name,QNameDef): if p.name.localName == "text": targetNodes = [XmlUtil.text(node)] # todo: add element, attribute, node, etc... targetSequence.extend(targetNodes) return targetSequence
def resultIsTable(self): result = XmlUtil.descendant(self, None, "result") if result is not None : child = XmlUtil.child(result, None, "table") if child is not None and XmlUtil.text(child).endswith(".xml"): return True return False
def resultTableUri(self): result = XmlUtil.descendant(self, None, "result") if result is not None: child = XmlUtil.child(result, None, "table") if child is not None: return os.path.join(self.modelDocument.outpath, XmlUtil.text(child)) return None
def viewFacts(self, modelFacts, indent): for modelFact in modelFacts: concept = modelFact.concept xmlRowElementName = 'item' attr = {"name": str(modelFact.qname)} if concept is not None and self.isCol0Label: lbl = concept.label(preferredLabel=self.labelrole, lang=self.lang, linkroleHint=XbrlConst.defaultLinkRole) xmlCol0skipElt = False # provide label as a row element else: lbl = (modelFact.qname or modelFact.prefixedName) # defective inline facts may have no qname xmlCol0skipElt = True # name is an attribute, don't do it also as an element cols = [lbl] if concept is not None: if modelFact.isItem: for col in self.cols[1:]: if col == "Label": # label or name may be 2nd to nth col if name or label is 1st col cols.append( concept.label(preferredLabel=self.labelrole, lang=self.lang) ) elif col == "Name": cols.append( modelFact.qname ) elif col == "contextRef": cols.append( modelFact.contextID ) elif col == "unitRef": cols.append( modelFact.unitID ) elif col == "Dec": cols.append( modelFact.decimals ) elif col == "Prec": cols.append( modelFact.precision ) elif col == "Lang": cols.append( modelFact.xmlLang ) elif col == "Value": cols.append( "(nil)" if modelFact.xsiNil == "true" else modelFact.effectiveValue.strip() ) elif col == "EntityScheme": cols.append( modelFact.context.entityIdentifier[0] ) elif col == "EntityIdentifier": cols.append( modelFact.context.entityIdentifier[1] ) elif col == "Start": cols.append( XmlUtil.text(XmlUtil.child(modelFact.context.period, XbrlConst.xbrli, "startDate")) ) elif col == "End/Instant": cols.append( XmlUtil.text(XmlUtil.child(modelFact.context.period, XbrlConst.xbrli, ("endDate","instant"))) ) elif col == "Dimensions": for dimQname in sorted(modelFact.context.qnameDims.keys()): cols.append( str(dimQname) ) cols.append( str(modelFact.context.dimMemberQname(dimQname)) ) elif modelFact.isTuple: xmlRowElementName = 'tuple' self.addRow(cols, treeIndent=indent, xmlRowElementName=xmlRowElementName, xmlRowEltAttr=attr, xmlCol0skipElt=xmlCol0skipElt) self.viewFacts(modelFact.modelTupleFacts, indent + 1)
def referenceURI(concept): for refrel in concept.modelXbrl.relationshipSet(XbrlConst.conceptReference).fromModelObject(concept): ref = refrel.toModelObject if ref is not None: for resourceElt in ref.iter(): if isinstance(resourceElt,ModelObject) and resourceElt.localName == "URI": return XmlUtil.text(resourceElt) return None
def resultInfosetUri(self): result = XmlUtil.descendant(self, None, "result") if result is not None: child = XmlUtil.child(result, None, "file") return os.path.join( self.modelDocument.outpath, XmlUtil.text(child if child is not None else result)) return None
def dir(self): self.open() if not self.isOpen: return None elif self.filesDir is not None: return self.filesDir elif self.isZip: files = [] for zipinfo in self.fs.infolist(): files.append(zipinfo.filename) self.filesDir = files elif self.isXfd: files = [] for data in self.xfdDocument.getElementsByTagName("data"): outfn = XmlUtil.text(data.getElementsByTagName("filename")[0]) if len(outfn) > 1: if len(outfn) > 2 and outfn[0].isalpha() and \ outfn[1] == ':' and outfn[2] == '\\': continue files.append(outfn); self.filesDir = files elif self.isRss: files = [] # return title, descr, pubdate, linst doc edgr = "http://www.sec.gov/Archives/edgar" try: for dsElt in self.rssDocument.getElementsByTagName("item"): instDoc = None for instDocElt in XmlUtil.descendants(dsElt, edgr, "xbrlFile"): if instDocElt.getAttributeNS(edgr,"description").endswith("INSTANCE DOCUMENT"): instDoc = instDocElt.getAttributeNS(edgr,"url") break if not instDoc: continue files.append(( XmlUtil.text(XmlUtil.descendant(dsElt, None, "title")), # tooltip "{0}\n {1}\n {2}\n {3}\n {4}".format( XmlUtil.text(XmlUtil.descendant(dsElt, edgr, "companyName")), XmlUtil.text(XmlUtil.descendant(dsElt, edgr, "formType")), XmlUtil.text(XmlUtil.descendant(dsElt, edgr, "filingDate")), XmlUtil.text(XmlUtil.descendant(dsElt, edgr, "cikNumber")), XmlUtil.text(XmlUtil.descendant(dsElt, edgr, "period"))), XmlUtil.text(XmlUtil.descendant(dsElt, None, "description")), XmlUtil.text(XmlUtil.descendant(dsElt, None, "pubDate")), instDoc)) self.filesDir = files except (EnvironmentError, xml.parsers.expat.ExpatError, xml.dom.DOMException) as err: pass return self.filesDir
def measure_name(xc, p, args): if len(args) != 1: raise XPathContext.FunctionNumArgs() if len(args[0]) != 1: raise XPathContext.FunctionArgType(1,"xbrl:measure") unit = args[0][0] if isinstance(unit,ModelObject) and \ unit.localName == "measure" and unit.namespaceURI == XbrlConst.xbrli: return qname(unit, XmlUtil.text(unit)) raise XPathContext.FunctionArgType(1,"xbrl:unit")
def resultIsInfoset(self): if self.modelDocument.outpath: result = XmlUtil.descendant(self, None, "result") if result is not None: return XmlUtil.child(result, None, "file") is not None or XmlUtil.text( result).endswith(".xml") return False
def resultXbrlInstanceUri(self): for pluginXbrlMethod in pluginClassMethods("ModelTestcaseVariation.ResultXbrlInstanceUri"): resultInstanceUri = pluginXbrlMethod(self) if resultInstanceUri is not None: return resultInstanceUri or None # (empty string returns None) resultInstance = XmlUtil.descendant(XmlUtil.descendant(self, None, "result"), None, "instance") if resultInstance is not None: return XmlUtil.text(resultInstance) return None
def acceptanceDatetime(self): try: return self._acceptanceDatetime except AttributeError: import datetime self._acceptanceDatetime = None date = XmlUtil.text(XmlUtil.descendant(self, edgr, u"acceptanceDatetime")) if date and len(date) == 14: self._acceptanceDatetime = datetime.datetime(_INT(date[0:4]),_INT(date[4:6]),_INT(date[6:8]),_INT(date[8:10]),_INT(date[10:12]),_INT(date[12:14])) return self._acceptanceDatetime
def filingDate(self): try: return self._filingDate except AttributeError: import datetime self._filingDate = None date = XmlUtil.text(XmlUtil.descendant(self, edgr, "filingDate")) d = date.split("/") if d and len(d) == 3: self._filingDate = datetime.date(_INT(d[2]),_INT(d[0]),_INT(d[1])) return self._filingDate
def xEqual(modelConcept1, node1, node2, equalMode=S_EQUAL, modelConcept2=None): text1 = XmlUtil.text(node1) text2 = XmlUtil.text(node2) baseXsdType1 = modelConcept1.baseXsdType if modelConcept1 else None if modelConcept1: baseXsdType1 = modelConcept1.baseXsdType if len(text1) == 0 and modelConcept1.default is not None: text1 = modelConcept1.default if not modelConcept2: modelConcept2 = modelConcept1 else: baseXsdType1 = None if modelConcept2: baseXsdType2 = modelConcept2.baseXsdType if len(text2) == 0 and modelConcept2.default is not None: text1 = modelConcept2.default else: baseXsdType2 = None return (xTypeValue(baseXsdType1, node1, node1, text1, equalMode) == xTypeValue(baseXsdType2, node2, node2, text2, equalMode))
def stringArg(xc, args, i, type, missingArgFallback=None, emptyFallback=''): item = anytypeArg(xc, args, i, type, missingArgFallback) if item == (): return emptyFallback if isinstance(item, xml.dom.Node): if item.nodeType == xml.dom.Node.ELEMENT_NODE: return XmlUtil.text(item) elif item.nodeType == xml.dom.Node.ATTRIBUTE_NODE: return item.value else: return "" return str(item)
def file(self,filepath): archiveFileSource = self.fileSourceContainingFilepath(filepath) if archiveFileSource is not None: if filepath.startswith(archiveFileSource.basefile): archiveFileName = filepath[len(archiveFileSource.basefile) + 1:] else: # filepath.startswith(self.baseurl) archiveFileName = filepath[len(archiveFileSource.baseurl) + 1:] if archiveFileSource.isZip: b = archiveFileSource.fs.read(archiveFileName) return io.TextIOWrapper( io.BytesIO(b), encoding=XmlUtil.encoding(b)) elif archiveFileSource.isXfd: for data in archiveFileSource.xfdDocument.getElementsByTagName("data"): outfn = XmlUtil.text(data.getElementsByTagName("filename")[0]) b64data = XmlUtil.text(data.getElementsByTagName("mimedata")[0]) if len(outfn) > 1 and len(b64data) > 1 and outfn == archiveFileName: # convert to bytes #byteData = [] #for c in b64data: # byteData.append(ord(c)) b = base64.b64decode(b64data.encode("latin-1")) # remove BOM codes if present if len(b) > 3 and b[0] == 239 and b[1] == 187 and b[2] == 191: start = 3; length = len(b) - 3; b = b[start:start + length] else: start = 0; length = len(b); # pass back as ascii #str = "" #for bChar in b[start:start + length]: # str += chr( bChar ) #return str return io.TextIOWrapper( io.BytesIO(b), encoding=XmlUtil.encoding(b)) return None return open(filepath, 'rt', encoding='utf-8')
def stepAxis(self, op, p, sourceSequence): targetSequence = [] for node in sourceSequence: if not isinstance(node,(ModelObject, etree._ElementTree, ModelAttribute)): raise XPathException(self.progHeader, 'err:XPTY0020', _('Axis step {0} context item is not a node: {1}').format(op, node)) targetNodes = [] if isinstance(p,QNameDef): ns = p.namespaceURI; localname = p.localName if p.isAttribute: if isinstance(node,ModelObject): attrTag = p.localName if p.unprefixed else p.clarkNotation modelAttribute = None try: modelAttribute = node.xAttributes[attrTag] except (AttributeError, TypeError, IndexError, KeyError): # may be lax or deferred validated try: validate(node.modelXbrl, node, p) modelAttribute = node.xAttributes[attrTag] except (AttributeError, TypeError, IndexError, KeyError): pass if modelAttribute is None: value = node.get(attrTag) if value is not None: targetNodes.append(ModelAttribute(node,p.clarkNotation,UNKNOWN,value,value,value)) elif modelAttribute.xValid >= VALID: targetNodes.append(modelAttribute) elif op == '/' or op is None: if isinstance(node,(ModelObject, etree._ElementTree)): targetNodes = XmlUtil.children(node, ns, localname) elif op == '//': if isinstance(node,(ModelObject, etree._ElementTree)): targetNodes = XmlUtil.descendants(node, ns, localname) elif op == '..': if isinstance(node,ModelAttribute): targetNodes = [ node.modelElement ] else: targetNodes = [ XmlUtil.parent(node) ] elif isinstance(p, OperationDef) and isinstance(p.name,QNameDef): if isinstance(node,ModelObject): if p.name.localName == "text": targetNodes = [XmlUtil.text(node)] # todo: add element, attribute, node, etc... elif p == '*': # wildcard if op == '/' or op is None: if isinstance(node,(ModelObject, etree._ElementTree)): targetNodes = XmlUtil.children(node, '*', '*') elif op == '//': if isinstance(node,(ModelObject, etree._ElementTree)): targetNodes = XmlUtil.descendants(node, '*', '*') targetSequence.extend(targetNodes) return targetSequence
def dateTime(value, time=None, addOneDay=None, type=None, castException=None): if value == "MinDate": return DateTime(datetime.MINYEAR,1,1) elif value == "maxyear": return DateTime(datetime.MAXYEAR,12,31) elif isinstance(value, xml.dom.Node): if value.nodeType == xml.dom.Node.ELEMENT_NODE: from arelle import (XmlUtil) value = XmlUtil.text(value) elif value.nodeType == xml.dom.Node.ATTRIBUTE_NODE: value = value.value else: value = None elif isinstance(value, DateTime) and not addOneDay and (value.dateOnly == (type == DATE)): return value # no change needed for cast or conversion elif isinstance(value, datetime.datetime): if type == DATE: dateOnly = True elif type == DATETIME: dateOnly = False else: dateOnly = isinstance(value, DateTime) and value.dateOnly if addOneDay and not dateOnly: addOneDay = False return DateTime(value.year, value.month, value.day, value.hour, value.minute, value.second, value.microsecond, tzinfo=value.tzinfo, dateOnly=dateOnly, addOneDay=addOneDay) elif isinstance(value, datetime.date): return DateTime(value.year, value.month, value.day,dateOnly=True,addOneDay=addOneDay) elif castException and not isinstance(value, str): raise castException if value is None: return None match = datetimePattern.match(value.strip()) if match is None: if castException: raise castException return None if match.lastindex == 6: if type == DATE: if castException: raise castException return None result = DateTime(int(match.group(1)),int(match.group(2)),int(match.group(3)),int(match.group(4)),int(match.group(5)),int(match.group(6)), dateOnly=False) else: if type == DATE or type == DATEUNION: dateOnly = True elif type == DATETIME: dateOnly = False else: dateOnly = False result = DateTime(int(match.group(7)),int(match.group(8)),int(match.group(9)),dateOnly=dateOnly,addOneDay=addOneDay) return result
def viewFacts(self, modelFacts, indent): for modelFact in modelFacts: concept = modelFact.concept if concept is not None and self.isCol0Label: lbl = concept.label(lang=self.lang) else: lbl = modelFact.qname cols = indent + [lbl] for i in range(self.treeCols - len(cols)): cols.append(None) if concept is not None and not modelFact.concept.isTuple: for col in self.cols[1:]: if col == "contextRef": cols.append( modelFact.contextID ) elif col == "unitRef": cols.append( modelFact.unitID ) elif col == "Dec": cols.append( modelFact.decimals ) elif col == "Prec": cols.append( modelFact.precision ) elif col == "Lang": cols.append( modelFact.xmlLang ) elif col == "Value": cols.append( "(nil)" if modelFact.xsiNil == "true" else modelFact.effectiveValue.strip() ) elif col == "EntityScheme": cols.append( modelFact.context.entityIdentifier[0] ) elif col == "EntityIdentifier": cols.append( modelFact.context.entityIdentifier[1] ) elif col == "Start": cols.append( XmlUtil.text(XmlUtil.child(modelFact.context.period, XbrlConst.xbrli, "startDate")) ) elif col == "End/Instant": cols.append( XmlUtil.text(XmlUtil.child(modelFact.context.period, XbrlConst.xbrli, ("endDate","instant"))) ) elif col == "Dimensions": for dimQname in sorted(modelFact.context.qnameDims.keys()): cols.append( str(dimQname) ) cols.append( str(modelFact.context.dimMemberQname(dimQname)) ) self.write(cols) self.viewFacts(modelFact.modelTupleFacts, indent + [None])
def expected(self): for pluginXbrlMethod in pluginClassMethods("ModelTestcaseVariation.ExpectedResult"): expected = pluginXbrlMethod(self) if expected: return expected # default behavior without plugins if self.localName == "testcase": return self.document.basename[:4] #starts with PASS or FAIL elif self.localName == "testGroup": #w3c testcase instanceTestElement = XmlUtil.descendant(self, None, "instanceTest") if instanceTestElement is not None: # take instance first return XmlUtil.descendantAttr(instanceTestElement, None, "expected", "validity") else: schemaTestElement = XmlUtil.descendant(self, None, "schemaTest") if schemaTestElement is not None: return XmlUtil.descendantAttr(schemaTestElement, None, "expected", "validity") resultElement = XmlUtil.descendant(self, None, "result") if resultElement is not None: expected = resultElement.get("expected") if expected and resultElement.get("nonStandardErrorCodes") == "true": # if @expected and @nonStandardErrorCodes then use expected instead of error codes return expected errorElement = XmlUtil.descendant(self, None, "error") resultElement = XmlUtil.descendant(self, None, "result") if errorElement is not None and not errorElement.get("nonStandardErrorCodes"): _errorText = XmlUtil.text(errorElement) if ' ' in _errorText: # list of tokens return _errorText return ModelValue.qname(errorElement, _errorText) # turn into a QName if resultElement is not None: if expected: return expected for assertElement in XmlUtil.children(resultElement, None, "assert"): num = assertElement.get("num") if num == "99999": # inline test, use name as expected return assertElement.get("name") if len(num) == 5: return "EFM.{0}.{1}.{2}".format(num[0],num[1:3],num[3:6]) asserTests = {} for atElt in XmlUtil.children(resultElement, None, "assertionTests"): try: asserTests[atElt.get("assertionID")] = (_INT(atElt.get("countSatisfied")),_INT(atElt.get("countNotSatisfied"))) except ValueError: pass if asserTests: return asserTests elif self.get("result"): return self.get("result") return None
def header(self, role=None, lang=None, evaluate=True, returnGenLabel=True, returnMsgFormatString=False): # if ord is a nested selectionAxis selection, use selection-message or text contents instead of axis headers isZSelection = isinstance(self._definitionNode, ModelSelectionDefinitionNode) and hasattr(self, "zSelection") if role is None: # check for message before checking for genLabel msgsRelationshipSet = self._definitionNode.modelXbrl.relationshipSet( (XbrlConst.tableDefinitionNodeSelectionMessage, XbrlConst.tableAxisSelectionMessage2011) if isZSelection else (XbrlConst.tableDefinitionNodeMessage, XbrlConst.tableAxisMessage2011)) if msgsRelationshipSet: msg = msgsRelationshipSet.label(self._definitionNode, XbrlConst.standardMessage, lang, returnText=False) if msg is not None: if evaluate: if returnMsgFormatString: return msg.formatString # not possible to evaluate (during resolution) else: return self.evaluate(msg, msg.evaluate) else: return XmlUtil.text(msg) if isZSelection: # no message, return text of selection return self.variables.get(self._definitionNode.variableQname, "selection") if returnGenLabel: label = self._definitionNode.genLabel(role=role, lang=lang) if label: return label # if there's a child roll up, check for it if self.rollUpStructuralNode is not None: # check the rolling-up child too return self.rollUpStructuralNode.header(role, lang, evaluate, returnGenLabel, returnMsgFormatString) # if aspect is a concept of dimension, return its standard label concept = None for aspect in self.aspectsCovered(): if isinstance(aspect, QName) or aspect == Aspect.CONCEPT: # dimension or concept aspectValue = self.aspectValue(aspect) if isinstance(aspectValue, QName): concept = self.modelXbrl.qnameConcepts[aspectValue] break elif isinstance(aspectValue, ModelDimensionValue): if aspectValue.isExplicit: concept = aspectValue.member elif aspectValue.isTyped: return XmlUtil.innerTextList(aspectValue.typedMember) if concept is not None: label = concept.label(lang=lang) if label: return label # if there is a role, check if it's available on a parent node if role and self.parentStructuralNode is not None: return self.parentStructuralNode.header(role, lang, evaluate, returnGenLabel, returnMsgFormatString) return None
def header(self, role=None, lang=None, strip=False, evaluate=True): if role is None: # check for message before checking for genLabel msgsRelationshipSet = self.modelXbrl.relationshipSet((XbrlConst.tableDefinitionNodeMessage, XbrlConst.tableAxisMessage2011)) if msgsRelationshipSet: msg = msgsRelationshipSet.label(self, XbrlConst.standardMessage, lang, returnText=False) if msg is not None: if evaluate: result = msg.evaluate(self.modelXbrl.rendrCntx) else: result = XmlUtil.text(msg) if strip: return result.strip() return result return self.genLabel(role=role, lang=lang, strip=strip)
def parent_child(args, parentName, childName, findDescendant=False): if len(args) != 1: raise XPathContext.FunctionNumArgs() if len(args[0]) != 1: raise XPathContext.FunctionArgType(1,"xbrl:" + parentName) parent = args[0][0] if isinstance(parent,ModelObject) and \ parent.localName == parentName and parent.namespaceURI == XbrlConst.xbrli: if childName.startswith('@'): return parent.get(childName[1:]) elif childName == 'text()': return XmlUtil.textNotStripped(parent) elif childName == 'strip-text()': return XmlUtil.text(parent) elif findDescendant: return XmlUtil.descendant(parent, XbrlConst.xbrli, childName) else: return XmlUtil.child(parent, XbrlConst.xbrli, childName) raise XPathContext.FunctionArgType(1,"xbrl:" + parentName)
def header(self, role=None, lang=None, evaluate=True, returnGenLabel=True): # if ord is a nested selectionAxis selection, use selection-message or text contents instead of axis headers isZSelection = isinstance(self._axisObject, ModelSelectionAxis) and hasattr(self, "zSelection") if role is None: # check for message before checking for genLabel msgsRelationshipSet = self._axisObject.modelXbrl.relationshipSet( XbrlConst.tableAxisSelectionMessage if isZSelection else XbrlConst.tableAxisMessage) if msgsRelationshipSet: msg = msgsRelationshipSet.label(self._axisObject, XbrlConst.standardMessage, lang, returnText=False) if msg is not None: if evaluate: return self.evaluate(msg, msg.evaluate) else: return XmlUtil.text(msg) if isZSelection: # no message, return text of selection return self.variables.get(self._axisObject.variableQname, "selection") if returnGenLabel: return self._axisObject.genLabel(role=role, lang=lang) return None
def dir(self): self.open() if not self.isOpen: return None elif self.filesDir is not None: return self.filesDir elif self.isZip: files = [] for zipinfo in self.fs.infolist(): f = zipinfo.filename if '\\' in f: self.isZipBackslashed = True f = f.replace("\\", "/") files.append(f) self.filesDir = files elif self.isTarGz: self.filesDir = self.fs.getnames() elif self.isEis: files = [] for docElt in self.eisDocument.iter( tag="{http://www.sec.gov/edgar/common}document"): outfn = docElt.findtext( "{http://www.sec.gov/edgar/common}conformedName") if outfn: files.append(outfn) self.filesDir = files elif self.isXfd: files = [] for data in self.xfdDocument.iter(tag="data"): outfn = data.findtext("filename") if outfn: if len(outfn) > 2 and outfn[0].isalpha() and \ outfn[1] == ':' and outfn[2] == '\\': continue files.append(outfn) self.filesDir = files elif self.isRss: files = [] # return title, descr, pubdate, linst doc edgr = "http://www.sec.gov/Archives/edgar" try: for dsElt in XmlUtil.descendants(self.rssDocument, None, "item"): instDoc = None for instDocElt in XmlUtil.descendants( dsElt, edgr, "xbrlFile"): if instDocElt.get( "(http://www.sec.gov/Archives/edgar}description" ).endswith("INSTANCE DOCUMENT"): instDoc = instDocElt.get( "(http://www.sec.gov/Archives/edgar}url") break if not instDoc: continue files.append(( XmlUtil.text(XmlUtil.descendant(dsElt, None, "title")), # tooltip "{0}\n {1}\n {2}\n {3}\n {4}".format( XmlUtil.text( XmlUtil.descendant(dsElt, edgr, "companyName")), XmlUtil.text( XmlUtil.descendant(dsElt, edgr, "formType")), XmlUtil.text( XmlUtil.descendant(dsElt, edgr, "filingDate")), XmlUtil.text( XmlUtil.descendant(dsElt, edgr, "cikNumber")), XmlUtil.text( XmlUtil.descendant(dsElt, edgr, "period"))), XmlUtil.text( XmlUtil.descendant(dsElt, None, "description")), XmlUtil.text(XmlUtil.descendant( dsElt, None, "pubDate")), instDoc)) self.filesDir = files except (EnvironmentError, etree.LxmlError) as err: pass elif self.isInstalledTaxonomyPackage: files = [] baseurlPathLen = len(os.path.dirname(self.baseurl)) + 1 def packageDirsFiles(dir): for file in os.listdir(dir): path = dir + "/" + file # must have / and not \\ even on windows files.append(path[baseurlPathLen:]) if os.path.isdir(path): packageDirsFiles(path) packageDirsFiles(self.baseurl[0:baseurlPathLen - 1]) self.filesDir = files return self.filesDir
def validate(val, modelXbrl, infosetModelXbrl): infoset = infosetModelXbrl.modelDocument if infoset.type == Type.INSTANCE: # compare facts (assumed out of order) infosetFacts = defaultdict(list) for fact in infosetModelXbrl.facts: infosetFacts[fact.qname].append(fact) if len(modelXbrl.factsInInstance) != len( infosetModelXbrl.factsInInstance): modelXbrl.error( "arelle:infosetTest", _("Fact counts mismatch, testcase instance %(foundFactCount)s, infoset instance %(expectedFactCount)s" ), modelObject=(modelXbrl.modelDocument, infosetModelXbrl.modelDocument), foundFactCount=len(modelXbrl.factsInInstance), expectedFactCount=len(infosetModelXbrl.factsInInstance)) else: for i, instFact in enumerate(modelXbrl.facts): infosetFact = None for fact in infosetFacts[instFact.qname]: if fact.isTuple and fact.isDuplicateOf(instFact, deemP0Equal=True): infosetFact = fact break elif fact.isItem and fact.isVEqualTo(instFact, deemP0Equal=True): infosetFact = fact break if infosetFact is None: # takes precision/decimals into account if fact is not None: fact.isVEqualTo(instFact, deemP0Equal=True) modelXbrl.error( "arelle:infosetTest", _("Fact %(factNumber)s mismatch %(concept)s"), modelObject=instFact, factNumber=(i + 1), concept=instFact.qname) else: ptvPeriodType = infosetFact.get( "{http://www.xbrl.org/2003/ptv}periodType") ptvBalance = infosetFact.get( "{http://www.xbrl.org/2003/ptv}balance") ptvDecimals = infosetFact.get( "{http://www.xbrl.org/2003/ptv}decimals") ptvPrecision = infosetFact.get( "{http://www.xbrl.org/2003/ptv}precision") if ptvPeriodType and ptvPeriodType != instFact.concept.periodType: modelXbrl.error( "arelle:infosetTest", _("Fact %(factNumber)s periodType mismatch %(concept)s expected %(expectedPeriodType)s found %(foundPeriodType)s" ), modelObject=(instFact, infosetFact), factNumber=(i + 1), concept=instFact.qname, expectedPeriodType=ptvPeriodType, foundPeriodType=instFact.concept.periodType) if ptvBalance and ptvBalance != instFact.concept.balance: modelXbrl.error( "arelle:infosetTest", _("Fact %(factNumber)s balance mismatch %(concept)s expected %(expectedBalance)s found %(foundBalance)s" ), modelObject=(instFact, infosetFact), factNumber=(i + 1), concept=instFact.qname, expectedBalance=ptvBalance, foundBalance=instFact.concept.balance) if ptvDecimals and ptvDecimals != str( inferredDecimals(fact)): modelXbrl.error( "arelle:infosetTest", _("Fact %(factNumber)s inferred decimals mismatch %(concept)s expected %(expectedDecimals)s found %(inferredDecimals)s" ), modelObject=(instFact, infosetFact), factNumber=(i + 1), concept=instFact.qname, expectedDecimals=ptvDecimals, inferredDecimals=str(inferredDecimals(fact))) if ptvPrecision and ptvPrecision != str( inferredPrecision(fact)): modelXbrl.error( "arelle:infosetTest", _("Fact %(factNumber)s inferred precision mismatch %(concept)s expected %(expectedPrecision)s found %(inferredPrecision)s" ), modelObject=(instFact, infosetFact), factNumber=(i + 1), concept=instFact.qname, expectedPrecisions=ptvPrecision, inferredPrecision=str(inferredPrecision(fact))) elif infoset.type == Type.ARCSINFOSET: # compare arcs for arcElt in XmlUtil.children(infoset.xmlRootElement, "http://www.xbrl.org/2003/ptv", "arc"): linkType = arcElt.get("linkType") arcRole = arcElt.get("arcRole") extRole = arcElt.get("extRole") fromObj = resolvePath(modelXbrl, arcElt.get("fromPath")) if fromObj is None: modelXbrl.error("arelle:infosetTest", _("Arc fromPath not found: %(fromPath)s"), modelObject=arcElt, fromPath=arcElt.get("fromPath")) continue if linkType in ("label", "reference"): labelLang = arcElt.get("labelLang") resRole = arcElt.get("resRole") if linkType == "label": expectedLabel = XmlUtil.text(arcElt) foundLabel = fromObj.label(preferredLabel=resRole, fallbackToQname=False, lang=None, strip=True, linkrole=extRole) if foundLabel != expectedLabel: modelXbrl.error( "arelle:infosetTest", _("Label expected='%(expectedLabel)s', found='%(foundLabel)s'" ), modelObject=arcElt, expectedLabel=expectedLabel, foundLabel=foundLabel) continue elif linkType == "reference": expectedRef = XmlUtil.innerText(arcElt) referenceFound = False for refrel in modelXbrl.relationshipSet( XbrlConst.conceptReference, extRole).fromModelObject(fromObj): ref = refrel.toModelObject if resRole == ref.role: foundRef = XmlUtil.innerText(ref) if foundRef != expectedRef: modelXbrl.error( "arelle:infosetTest", _("Reference inner text expected='%(expectedRef)s, found='%(foundRef)s'" ), modelObject=arcElt, expectedRef=expectedRef, foundRef=foundRef) referenceFound = True break if referenceFound: continue modelXbrl.error( "arelle:infosetTest", _("%(linkType)s not found containing '%(text)s' linkRole %(linkRole)s" ), modelObject=arcElt, linkType=linkType.title(), text=XmlUtil.innerText(arcElt), linkRole=extRole) else: toObj = resolvePath(modelXbrl, arcElt.get("toPath")) if toObj is None: modelXbrl.error("arelle:infosetTest", _("Arc toPath not found: %(toPath)s"), modelObject=arcElt, toPath=arcElt.get("toPath")) continue weight = arcElt.get("weight") if weight is not None: weight = float(weight) order = arcElt.get("order") if order is not None: order = float(order) preferredLabel = arcElt.get("preferredLabel") found = False for rel in modelXbrl.relationshipSet( arcRole, extRole).fromModelObject(fromObj): if (rel.toModelObject == toObj and (weight is None or rel.weight == weight) and (order is None or rel.order == order)): found = True if not found: modelXbrl.error( "arelle:infosetTest", _("Arc not found: from %(fromPath)s, to %(toPath)s, role %(arcRole)s, linkRole $(extRole)s" ), modelObject=arcElt, fromPath=arcElt.get("fromPath"), toPath=arcElt.get("toPath"), arcRole=arcRole, linkRole=extRole) continue # validate dimensions of each fact factElts = XmlUtil.children(modelXbrl.modelDocument.xmlRootElement, None, "*") for itemElt in XmlUtil.children(infoset.xmlRootElement, None, "item"): try: qnElt = XmlUtil.child(itemElt, None, "qnElement") factQname = qname(qnElt, XmlUtil.text(qnElt)) sPointer = int(XmlUtil.child(itemElt, None, "sPointer").text) factElt = factElts[sPointer - 1] # 1-based xpath indexing if factElt.qname != factQname: modelXbrl.error( "arelle:infosetTest", _("Fact %(sPointer)s mismatch Qname, expected %(qnElt)s, observed %(factQname)s" ), modelObject=itemElt, sPointer=sPointer, qnElt=factQname, factQname=factElt.qname) elif not factElt.isItem or factElt.context is None: modelXbrl.error( "arelle:infosetTest", _("Fact %(sPointer)s has no context: %(qnElt)s"), modelObject=(itemElt, factElt), sPointer=sPointer, qnElt=factQname) else: context = factElt.context memberElts = XmlUtil.children(itemElt, None, "member") numNonDefaults = 0 for memberElt in memberElts: dimElt = XmlUtil.child(memberElt, None, "qnDimension") qnDim = qname(dimElt, XmlUtil.text(dimElt)) isDefault = XmlUtil.text( XmlUtil.child(memberElt, None, "bDefaulted")) == "true" if not isDefault: numNonDefaults += 1 if not ( (qnDim in context.qnameDims and not isDefault) or (qnDim in factElt.modelXbrl.qnameDimensionDefaults and isDefault)): modelXbrl.error( "arelle:infosetTest", _("Fact %(sPointer)s (qnElt)s dimension mismatch %(qnDim)s" ), modelObject=(itemElt, factElt, context), sPointer=sPointer, qnElt=factQname, qnDim=qnDim) if numNonDefaults != len(context.qnameDims): modelXbrl.error( "arelle:infosetTest", _("Fact %(sPointer)s (qnElt)s dimensions count mismatch" ), modelObject=(itemElt, factElt, context), sPointer=sPointer, qnElt=factQname) except (IndexError, ValueError, AttributeError) as err: modelXbrl.error( "arelle:infosetTest", _("Invalid entity fact dimensions infoset sPointer: %(test)s, error details: %(error)s" ), modelObject=itemElt, test=XmlUtil.innerTextList(itemElt), error=str(err))
def fiscalYearEnd(self): yrEnd = XmlUtil.text(XmlUtil.descendant(self, edgr, "fiscalYearEnd")) if yrEnd and len(yrEnd) == 4: return "{0}-{1}".format(yrEnd[0:2], yrEnd[2:4]) return None
def cikNumber(self): return XmlUtil.text(XmlUtil.descendant(self, edgr, "cikNumber"))
def accessionNumber(self): return XmlUtil.text(XmlUtil.descendant(self, edgr, "accessionNumber"))
def companyName(self): return XmlUtil.text(XmlUtil.descendant(self, edgr, "companyName"))
def formType(self): return XmlUtil.text(XmlUtil.descendant(self, edgr, "formType"))