def parseCat(self, filePath): """Parse a catalog given its full file path. Returns two items: - objCat: the catalog as a TUI.TCC.TelTarget.Catalog - errList: a list of (line, errMsg) tuples, one per rejected line of object data Raises RuntimeError if the file cannot be read or a default is invalid. Uses universal newline support (new in Python 2.3) if possible. """ # print "parseCat(%r)" % (filePath,) fp = RO.OS.openUniv(filePath) catName = os.path.basename(filePath) defOptionDict = self._keyMatcher.matchKeys({ "CSys": "FK5", "RotType": "Object", }) errList = [] objList = [] # save checkWdg data, then use try/finally to restore no matter what ii = 0 for line in fp: ii += 1 # print "Parsing object %d" % ii isDefault = False line = line.strip() try: if not line: # blank line continue elif line[0] in ("#", "!"): # comment continue elif line[0] in ('"', "'"): # data with quoted object name (objName, nextInd) = GetString.getString(line) pos1, pos2, optionStr = posOptionRE.match(line[nextInd:]).groups() else: # data with unquoted object name or default option match = namePosOptionRE.match(line) if match: # data with unquoted object name objName, pos1, pos2, optionStr = match.groups() elif line[0].isdigit(): raise ValueError("could not parse; is object name missing?") else: isDefault = True optionStr = line if optionStr: optDict = ParseData.parseKeyValueData(optionStr) else: optDict = {} if isDefault: # update existing defaults # merge new defaults into existing defaults # and check the result self._combineDicts(defOptionDict, optDict) else: # a line of data # the data dictionary starts with the current defaults dataDict = defOptionDict.copy() # add object name and position (non-dictionary items) dataDict.update({ "Name": objName, "ObjPos": (pos1, pos2), }) # merge new data with a copy of the defaults # and check the result self._combineDicts(dataDict, optDict) objList.append(TUI.TCC.TelTarget.TelTarget(dataDict)) except Exception, e: if isDefault: raise RuntimeError(RO.StringUtil.strFromException(e)) else: errList.append((line, RO.StringUtil.strFromException(e)))
def getValues(astr, begInd=0): """ Extracts all values (zero or more) for a keyword. Inputs: astr: the string to parse begInd: index of start, must point to "=" if the keyword has any values or ";" if the keyword has no values. Initial whitespace is skipped. Returns a duple consisting of: a tuple of values (empty if there are no values) the index of the beginning of the next keyword, or None if end of string Exceptions: If astr[begInd] is not "=" or ";" then raises a SyntaxError """ if begInd is None: return ((), None) mo = _StartRE.match(astr, begInd) if mo is None: raise SyntaxError("cannot find value(s) starting at %d in :%s:" % \ (begInd, astr)) sepChar = mo.group('first') nextInd = mo.start('next') if nextInd < 0: # no values and line finished return ((), None) if sepChar == ';': # no values; line not finished return ((), nextInd) valueList = [] prevInd = nextInd # print "data = :%s:, begInd = %d" % (astr, begInd) while True: # print "scanning :%s:, i.e. nextInd = %d" % (astr[nextInd:], nextInd) nextIsKey = False if astr[nextInd] in "\'\"": # value is a delimited string # print "looking for a delimited string" (value, nextInd) = GetString.getString(astr, nextInd) valueList.append(value) elif astr[nextInd] != ';': # value is an undelimited word (e.g. a number, NaN, etc.) # print "looking for an undelimited word starting at %d" % (nextInd) mo = _UndelimWordRE.match(astr, nextInd) if mo is None: raise SyntaxError("cannot find an undelimited word starting at %d in :%s:" % \ (nextInd, astr)) value = mo.group('str') nextInd = mo.start('next') if (nextInd < 0): nextInd = None valueList.append(value) # print "valueList =", valueList, "nextInd =", nextInd, # if nextInd is not None: # print "char at nextInd =", astr[nextInd] # else: # print "" if nextInd is None: # done with line break # nextInd points to comma or semicolon if astr[nextInd] == ';': nextIsKey = True elif astr[nextInd] != ',': print("bug; expected comma or semicolon as next token; giving up on line") nextInd = None break if (nextInd <= prevInd) and not nextIsKey: print("bug: nextInd = %d <= prevInd = %d" % (nextInd, prevInd)) nextInd = None break # find index of next character for ind in range(nextInd+1, len(astr)): if astr[ind] not in ' \t': nextInd = ind break else: print("ignoring separator \"%s\" at end of data :%s:" % \ (astr[nextInd], astr)) nextInd = None break if nextInd >= len(astr): break if nextIsKey: break prevInd = nextInd return (tuple(valueList), nextInd)
def parseCat(self, filePath): """Parse a catalog given its full file path. Returns two items: - objCat: the catalog as a TUI.TCC.TelTarget.Catalog - errList: a list of (line, errMsg) tuples, one per rejected line of object data Raises RuntimeError if the file cannot be read or a default is invalid. Uses universal newline support (new in Python 2.3) if possible. """ # print "parseCat(%r)" % (filePath,) fp = RO.OS.openUniv(filePath) catName = os.path.basename(filePath) defOptionDict = self._keyMatcher.matchKeys({ "CSys": "FK5", "RotType": "Object", }) errList = [] objList = [] # save checkWdg data, then use try/finally to restore no matter what ii = 0 for line in fp: ii += 1 # print "Parsing object %d" % ii isDefault = False line = line.strip() try: if not line: # blank line continue elif line[0] in ("#", "!"): # comment continue elif line[0] in ('"', "'"): # data with quoted object name (objName, nextInd) = GetString.getString(line) pos1, pos2, optionStr = posOptionRE.match( line[nextInd:]).groups() else: # data with unquoted object name or default option match = namePosOptionRE.match(line) if match: # data with unquoted object name objName, pos1, pos2, optionStr = match.groups() elif line[0].isdigit(): raise ValueError( "could not parse; is object name missing?") else: isDefault = True optionStr = line if optionStr: optDict = ParseData.parseKeyValueData(optionStr) else: optDict = {} if isDefault: # update existing defaults # merge new defaults into existing defaults # and check the result self._combineDicts(defOptionDict, optDict) else: # a line of data # the data dictionary starts with the current defaults dataDict = defOptionDict.copy() # add object name and position (non-dictionary items) dataDict.update({ "Name": objName, "ObjPos": (pos1, pos2), }) # merge new data with a copy of the defaults # and check the result self._combineDicts(dataDict, optDict) objList.append(TUI.TCC.TelTarget.TelTarget(dataDict)) except Exception as e: if isDefault: raise RuntimeError(RO.StringUtil.strFromException(e)) else: errList.append((line, RO.StringUtil.strFromException(e))) # convert catalog options as appropriate self._catOptions["doDisplay"] = RO.CnvUtil.asBool( self._catOptions["doDisplay"]) # create catalog # print "parseCat: catOptions =", self._catOptions objCat = TUI.TCC.TelTarget.Catalog(name=catName, objList=objList, **self._catOptions) # print "parseCat returning (%r, %r)" % (objCat, errList) return objCat, errList
def getValues(astr, begInd=0): """ Extracts all values (zero or more) for a keyword. Inputs: astr: the string to parse begInd: index of start, must point to "=" if the keyword has any values or ";" if the keyword has no values. Initial whitespace is skipped. Returns a duple consisting of: a tuple of values (empty if there are no values) the index of the beginning of the next keyword, or None if end of string Exceptions: If astr[begInd] is not "=" or ";" then raises a SyntaxError """ if begInd is None: return ((), None) mo = _StartRE.match(astr, begInd) if mo is None: raise SyntaxError("cannot find value(s) starting at %d in :%s:" % \ (begInd, astr)) sepChar = mo.group('first') nextInd = mo.start('next') if nextInd < 0: # no values and line finished return ((), None) if sepChar == ';': # no values; line not finished return ((), nextInd) valueList = [] prevInd = nextInd # print "data = :%s:, begInd = %d" % (astr, begInd) while True: # print "scanning :%s:, i.e. nextInd = %d" % (astr[nextInd:], nextInd) nextIsKey = False if astr[nextInd] in "\'\"": # value is a delimited string # print "looking for a delimited string" (value, nextInd) = GetString.getString(astr, nextInd) valueList.append(value) elif astr[nextInd] != ';': # value is an undelimited word (e.g. a number, NaN, etc.) # print "looking for an undelimited word starting at %d" % (nextInd) mo = _UndelimWordRE.match(astr, nextInd) if mo is None: raise SyntaxError("cannot find an undelimited word starting at %d in :%s:" % \ (nextInd, astr)) value = mo.group('str') nextInd = mo.start('next') if (nextInd < 0): nextInd = None valueList.append(value) # print "valueList =", valueList, "nextInd =", nextInd, # if nextInd is not None: # print "char at nextInd =", astr[nextInd] # else: # print "" if nextInd is None: # done with line break # nextInd points to comma or semicolon if astr[nextInd] == ';': nextIsKey = True elif astr[nextInd] != ',': print( "bug; expected comma or semicolon as next token; giving up on line" ) nextInd = None break if (nextInd <= prevInd) and not nextIsKey: print("bug: nextInd = %d <= prevInd = %d" % (nextInd, prevInd)) nextInd = None break # find index of next character for ind in range(nextInd + 1, len(astr)): if astr[ind] not in ' \t': nextInd = ind break else: print("ignoring separator \"%s\" at end of data :%s:" % \ (astr[nextInd], astr)) nextInd = None break if nextInd >= len(astr): break if nextIsKey: break prevInd = nextInd return (tuple(valueList), nextInd)