"""RhymingPandaUtil: basic utilities""" import string, types, sys, os, traceback import gzip, zipfile, datetime, time def CleanListOfStrings(lIncoming): """return list of lines cleaned of \\n""" if type(lIncoming) == types.ListType: lOutgoing = [] for eachline in lIncoming: if type(eachline) == types.StringType: #check that end should be cleaned of "\012" if len(eachline) > 1: #lOutgoing += [CleanForISBN(eachline)] lOutgoing += [string.strip(eachline)] return lOutgoing else: return lIncoming def CleanForISBN(sIncoming): """return nothing but valid ISBN characters from string""" if type(sIncoming) in (types.StringType, types.UnicodeType): sIncoming = string.strip(string.upper(sIncoming)) lReturn = [] #prep valid chars #svalidchars = string.digits[:] + "x" + "X" svalidchars = string.digits[:] + 'X' for eachchar in sIncoming: if eachchar in svalidchars: lReturn += [eachchar] #reformat into string return string.join(lReturn, "") def StripQuotes(sToClean): """Strip single & double quotes from both ends of string""" if type(sToClean) == types.StringType: sToClean = string.strip(sToClean) sInvalidChars = "'" + '"' #search from beginning while len(sToClean) > 0: if sToClean[0] in sInvalidChars: sToClean = sToClean[1:] else: break #search from end while len(sToClean) > 0: if sToClean[-1] in sInvalidChars: sToClean = sToClean[0:-1] else: break return string.strip(sToClean)#just to make sure we get embedded whitespace def StripToAlphaNumeric(sToClean): """return a string stripped of all whitespace & punctuation from both ends""" if type(sToClean) == types.StringType: sToClean = string.strip(sToClean) sInvalidChars = string.punctuation[:] + string.whitespace[:] + '[]' while len(sToClean) > 1: #move backwards if sToClean[-1] in sInvalidChars: sToClean = sToClean[0:-1] else: break while len(sToClean) > 1: #move forwards if sToClean[0] in sInvalidChars: sToClean = sToClean[1:] else: break return string.strip(sToClean)#just to make sure we get embedded whitespace def StripToNumeric(sToClean): """strip a string to its numeric components - from both sides""" if type(sToClean) == types.StringType: sx = StripToAlphaNumeric(sToClean) lreturn = [] for schar in sx: if schar in string.digits: lreturn += schar #attempt to convert to int try: vreturn = int(string.join(lreturn, '')) except: vreturn = sToClean #let caller check type return vreturn def StripToNumericFromLeft(sToClean): """strip a string to numbers only, stopping at the first alphabetic character""" if type(sToClean) == types.StringType: sx = StripToAlphaNumeric(sToClean) lreturn = [] for schar in sx: if schar in string.digits: lreturn += schar elif schar in (string.punctuation, string.whitespace): #ignore but continue pass else: break return string.join(lreturn, '') def escape_ampersand(text): "Escapes ampersands with additional ampersand for GUI" #from http://remotesensing.org/lists/ossim_archive/msg00931.html return string.replace(text, "&", "&&") def escape_quote(sText): return string.replace(sText, '"', '"') def TheToEnd(sTitle): """return the string with any beginning "the" switched to the end""" #print 'TheToEnd: %s [%s]' % (string.upper(string.strip(sTitle)), string.upper(string.strip(sTitle))[:2]) if string.upper(string.strip(sTitle))[:4] == 'THE ': #make sure it's a whole word! sX = string.strip(sTitle) sThe = sTitle[:3] sX = string.strip(sX[3:]) return '%s, %s' % (sX, sThe) else: return sTitle def ReturnList(vAnything = ''): """return vAnything as a list, if not already""" #print whoami() if type(vAnything) in (types.ListType, types.TupleType): return vAnything else: return [vAnything] def ClearInput(): """courtesy http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/82748""" # platform-dependent command to clear the display if sys.platform in ('linux-i386', 'linux2'): sClear = 'clear' elif sys.platform in ('win32', 'dos', 'ms-dos'): sClear = 'cls' # clear screen using system command if sClear: os.system(sClear) def GZipOrTextReadLines(sPathToFile): """given a file, return a line of strings, whether it's gzipped or not""" iSuccess = 0 lLines = [] if os.path.exists(sPathToFile): if not zipfile.is_zipfile(sPathToFile): sDir, sExt = os.path.splitext(sPathToFile) if string.lower(sExt) == '.gz': #open as gzip try: gzFile = gzip.GzipFile(sPathToFile) lLines = gzFile.readlines() gzFile.close() iSuccess = 1 except ValueError, sErrVal: print sErrVal iSuccess = 0 except: print traceback.print_exc() iSuccess = 0 else: #treat as text try: lLines = file(sPathToFile).readlines() iSuccess = 1 except: print traceback.print_exc() iSuccess = 0 else: #don't handle zips iSuccess = 0 return iSuccess, lLines #the following 2 courtesy http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66062 def whoami(): return sys._getframe(1).f_code.co_name def callersname(): return sys._getframe(2).f_code.co_name #following 2 courtesy http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/173220 text_characters = "".join(map(chr, range(32, 127)) + list("\n\r\t\b")) _null_trans = string.maketrans("", "") def istextfile(filename, blocksize = 512): return istext(file(filename).read(blocksize)) def istext(s): if "\0" in s: return 0 if not s: # Empty files are considered text return 1 # Get the non-text characters (maps a character to itself then # use the 'remove' option to get rid of the text characters.) t = s.translate(_null_trans, text_characters) # If more than 30% non-text characters, then # this is considered a binary file if len(t)/len(s) > 0.30: return 0 return 1 #courtesy http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 #(this is much faster for large sequences, using a dictionary, Clark Updike, 2003/03/08) def RemoveDupes(hasDupes=[]): import operator setitem = operator.setitem noDupes={} [operator.setitem(noDupes,repr(i),i) for i in hasDupes if not noDupes.has_key(repr(i))] noDupes = noDupes.values() return noDupes def average(values=[]): return sum(values, 0.0) / len(values) def todayasISO(): """return today's local date in ISO format: yyyy-mm-dd""" import datetime dteX = datetime.date.today() return dteX.isoformat() def convert2digitto4digityear(strYear): import datetime if type(strYear) in types.StringTypes and len(strYear) == 2: dteX = datetime.date.today() #convert 2digit to 4digit year if int(strYear) < 50: #add this century on to it strYear = '%s%s' % (str(dteX.year)[:-2], strYear) else: #last century strYear = '%s%s' % (str(dteX.year - 100)[:-2], strYear) return strYear def ExceptionInfo(intLevel=0): """return list of strings from traceback.format_X 0=full traceback; 1=traceback only (offending code); 2=exception only""" tplTB = sys.exc_info() if intLevel == 0 or intLevel not in (0,1,2): return traceback.format_exception(tplTB[0], tplTB[1], tplTB[2]) elif intLevel == 1: return traceback.format_tb(tplTB[2]) else: return traceback.format_exception_only(tplTB[0], tplTB[1]) def ziptime2utime(tplziptime=()): """take a time tuple from zipfile.ZipInfo and return utime equivalent 0 Year 1 Month (one-based) 2 Day of month (one-based) 3 Hours (zero-based) 4 Minutes (zero-based) 5 Seconds (zero-based)""" if type(tplziptime) in (types.ListType, types.TupleType): if len(tplziptime) == 6: #convert to datetime dteX = datetime.datetime(tplziptime[0], tplziptime[1], tplziptime[2], tplziptime[3], tplziptime[4], tplziptime[5]) #convert to utime-compatible format return time.mktime(dteX.timetuple()) #if here, incorrect params return None def friendlyelapsedtime(fltStart=0.0, fltEnd=0.0, blnShowSecondsFraction=False): """return friendly representation of seconds as string""" if type(fltStart) in (types.FloatType, types.IntType) and \ type(fltEnd) in (types.FloatType, types.IntType): try: # get total fltTotal = fltEnd - fltStart lstInfo = [0, 0, 0, 0] # get days intDivisor = 24*60*60 if (fltTotal-intDivisor) > 1: #lstInfo[0] = fltTotal/(24*60*60) lstInfo[0] = int(fltTotal/intDivisor) #fltTotal -= lstInfo[0] fltTotal = fltTotal%intDivisor # get hours intDivisor = 60**2 if (fltTotal-intDivisor) > 1: lstInfo[1] = int(fltTotal/intDivisor) fltTotal = fltTotal%intDivisor # get minutes intDivisor = 60 if (fltTotal-intDivisor) > 1: lstInfo[2] = int(fltTotal/intDivisor) fltTotal = fltTotal%intDivisor # get seconds lstInfo[3] = fltTotal if not blnShowSecondsFraction: lstInfo[3] = int(lstInfo[3]) #pretty print! #X days, HH:MM:SS.N if lstInfo[0] <> 1: # make plural lstInfo.insert(1, 's') else: lstInfo.index(1, '') if blnShowSecondsFraction: strReturn = '%s day%s, %02d:%02d:%00.02f' else: strReturn = '%s day%s, %02d:%02d:%02d' return strReturn % tuple(lstInfo) except: traceback.print_exc() return 'failed on these params: %s, %s' % (fltStart, fltEnd) else: return 'invalid params: expecting floats, received %s and %s' % (fltStart, fltEnd) def pickINIsection(strINIPath=''): """pick a section from INI""" import configobj try: objCFG = configobj.ConfigObj(strINIPath) print 'pick a section from the INI file %s' % os.path.split(strINIPath)[1] intCounter = 1 lstSections = [] for k, v in objCFG.items(): lstSections.append(k) print '\t%s> %s' % (intCounter, k) intCounter += 1 strChoice = raw_input('? ') try: strK = lstSections[int(strChoice)-1] #print 'you selected %s, which is %s' % (strChoice, strK) return True, strK except: traceback.print_exc() #print 'you selected an invalid option: %s' % strChoice return False, strChoice except: traceback.print_exc() return False, 'unknown error' def config_splitlist(strValue=''): """given a string in the form [value1,value2], split into list always returns a list""" try: #assert isinstance(strValue, string) if len(strValue) == 0: return [] strValue = strValue.strip('[]') return strValue.split(',') except: traceback.print_exc() return [] def getPeriodCount(dteStart, dteToCalc, strLengthType=''): """given a date (ISO string||mxDT object), return a number corresponding to the year, month, or week since the start date strLengthType accepts ('y', 'm', 'd')""" try: #convert dates to mxDT objects import mx.DateTime as mxDT if type(dteStart) in types.StringTypes: #convert from ISO to mxDT dteStart = mxDT.ISO.ParseDateTime(dteStart) if type(dteToCalc) in types.StringTypes: #convert from ISO to mxDT dteToCalc = mxDT.ISO.ParseDateTime(dteToCalc) ##make sure both are mxDT objects #assert isinstance(dteStart, mxDT.Date) #assert isinstance(dteToCalc, mxDT.Date) varRelativeDateDiff = mxDT.RelativeDateDiff(dteStart, dteToCalc) varDateDiff = dteStart - dteToCalc if strLengthType == 'y': return varRelativeDateDiff.years elif strLengthType == 'm': return (varRelativeDateDiff.years * 12) + varRelativeDateDiff.months elif strLengthType == 'd': return varDateDiff.days # varRelativeDateDiff.days else: return '%s not coded yet!' % strLengthType except StandardError, varErrValue: #traceback.print_exc() try: print '%s: %s' % (varErrValue.__doc__, varErrValue) except: pass return None def convertDateObject(objDate=None): """given either a datetime.date object or a mxDT.DateTime object, convert to the other format""" import mx.DateTime as mxDT if objDate == None: return None elif isinstance(objDate, datetime.datetime): dteReturn = mxDT.ISO.ParseDateTime(str(objDate.isoformat())) return dteReturn #elif isinstance(objDate, datetime.date): ## convert to mxDT #dteReturn = mxDT.Date(objDate.year, objDate.month, objDate.day) #return dteReturn elif type(objDate) == type(mxDT.Date(2000, 1, 1)): # convert to datetime try: dteReturn = datetime.date(objDate.year, objDate.month, objDate.day) return dteReturn except: traceback.print_exc() return None else: print whoami(), 'cannot determine date type: %s' % objDate return None def converttodatetime(objDate=None): """convert an object (mx.DateTime, built-in datetime, 10-character string in iso format) to built-in datetime""" try: if isinstance(objDate, datetime.date): return objDate elif type(objDate) in types.StringTypes and len(string.strip(objDate)) == 10: try: return datetime.date(int(objDate[0:4]), int(objDate[5:7]), int(objDate[8:])) except: return None else: import mx.DateTime as mxDT if type(objDate) == type(mxDT.Date(2000, 1, 1)): # convert to datetime return datetime.date(objDate.year, objDate.month, objDate.day) else: return None except: traceback.print_exc() return None def getISO8601str(dteAny=None): """given a valid mxDT object, convert to ISO8601 format (including T as date/time separator); if dteAny = None, use current time""" ##TODO: is this really RFC3339 format? try: import mx.DateTime as mxDT striso8601 = '' if dteAny == None: striso8601 = mxDT.ISO.str(mxDT.now()) else: striso8601 = mxDT.ISO.str(dteAny) # add colon to timezone offset if striso8601[-1] != 'Z': striso8601 = striso8601[:-2] + ':' + striso8601[-2:] return string.replace(striso8601, ' ', 'T', 1) except: traceback.print_exc() return '' def boolany(varvalue): """properly convert to True/False any value, including "True"/"False" strings""" try: if type(varvalue) in types.StringTypes: varvalue = string.lower(string.strip(varvalue)) if varvalue in ('true', '1'): return True elif varvalue in ('false', '0', ''): return False else: return None else: return bool(varvalue) except: return None def get_date(yr,mth,day): """basic date arithmetic usage: get_date(today.year, today.month-36, today.day) == 36 mths ago from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303441""" if mth<1: yr=yr-((abs(mth)/12)+1) mth=mth+((abs(mth)/12)+1)*12 if mth>12: yr=yr+(mth/12) mth=mth-(mth/12)*12 begin_mth= datetime.date(yr, mth, 1) return begin_mth + datetime.timedelta(day - 1) def commafynumber(thenumber, theformat='%.2f'): """commafy a number & return as string; use '%.0f' to return whole numbers""" try: import locale locale.setlocale(locale.LC_ALL, '') return locale.format(theformat, thenumber, 1) except: traceback.print_exc() return '' weekdays = {0: 'Monday', 1: 'Tuesday', 2: 'Wednesday', 3: 'Thursday', 4: 'Friday', 5: 'Saturday', 6: 'Sunday'} #today = datetime.date.today() #print 'now\t\t\t',get_date(today.year, today.month, today.day) #print '36 mths ago\t\t',get_date(today.year, today.month-36, today.day) #print '35 mths ago\t\t',get_date(today.year, today.month-35, today.day) #print '36 mths from now\t',get_date(today.year, today.month+36, today.day) #print '35 mths from now\t',get_date(today.year, today.month+35, today.day) #print '50 days ago\t\t',get_date(today.year, today.month, today.day-50) #print '2 years ago\t\t',get_date(today.year-2, today.month, today.day) if __name__ == '__main__': while True: lstTests = ['1 > todayasISO()', '2 > RemoveDupes', '3 > StripQuotes', '4 > ReturnList', '5 > ziptime2utime', '6 > friendlyelapsedtime', '7 > getPeriodCount', '8 > convertDateObject'] strSelection = raw_input('Select from the following tests:\n%s\n> ' % '\n'.join(lstTests)) if strSelection == '1': #todayasISO test print todayasISO() elif strSelection == '2': #RemoveDupes test try: lstCleaned = RemoveDupes(['123', '345', '546', '345']) print 'Removedupes: %s' % lstCleaned except: traceback.print_exc elif strSelection == '3': #StripQuotes test try: print StripQuotes('"unquote me!"') except: traceback.print_exc() elif strSelection == '4': try: print "\nwhoami() for __main__: %s" % whoami() print ReturnList(None) except: traceback.print_exc() elif strSelection == '5': #ziptim2utime test try: varX = ziptime2utime((2004, 7, 26, 18, 41, 0)) print varX #get mtime for a file varY = os.path.getmtime('rp_util.py') print varY #print time.mktime(varX) except: traceback.print_exc() elif strSelection == '6': # friendlyseconds test print 'show whole seconds: %s' % friendlyelapsedtime(1, (25*60*60)+488701.839) print 'show seconds fractions: %s' % friendlyelapsedtime(1, (25*60*60)+488701.839, True) print 'show whole seconds: %s' % friendlyelapsedtime(1, (25*60*60)+488721.839) print 'show seconds fractions: %s' % friendlyelapsedtime(1, (25*60*60)+488721.839, True) elif strSelection == '7': try: import mx.DateTime as mxDT #varX = '2004-10-12' ##varY = '2005-04-01' #varY = mxDT.Date(2006, 7, 12) #varResult = getPeriodCount(varX, varY, 'y') ##if varResult != None: ##print 'getPeriodCount result: %s' % varResult ##else: ##print 'getPeriodCount failed' #print 'getPeriodCount result (y): %s' % varResult #varResult = getPeriodCount(varX, varY, 'm') #print 'getPeriodCount result (y): %s' % varResult ClearInput() lstDatesToTest = [['2004-10-12', '2005-04-25'], ['1998-09-22', mxDT.now()], ['2004-10-12', '2005-03-19T10:24:48'], ['2004-10-12', '2005-09-12']] #['2004-10-12', '2005-03-19T10_24_48'], lstPeriodsToTest = 'ymwd' for lstToTest in lstDatesToTest: for strPeriod in lstPeriodsToTest: varResult = getPeriodCount(lstToTest[0], lstToTest[1], strPeriod) print '\t%s; %s; %s: %s %s' % (lstToTest[0], lstToTest[1], strPeriod, varResult, type(varResult)) except: traceback.print_exc() elif strSelection == '8': # convertDateObject print 'datetime to mxDT' objDate1 = datetime.date(2005, 1, 1) var1 = convertDateObject(objDate1) print 'original: %s, %s' % (objDate1, type(objDate1)) print 'result: %s, %s' % (var1, type(var1)) print 'mxDT to datetime' import mx.DateTime as mxDT objDate2 = mxDT.Date(2005, 2, 2) var2 = convertDateObject(objDate2) print 'original: %s, %s' % (objDate2, type(objDate2)) print 'result: %s, %s' % (var2, type(var2)) else: # not in list, aborting break