syncplay/syncplay/utils.py
2014-07-03 00:20:31 +02:00

183 lines
6.3 KiB
Python

import time
import re
import datetime
from syncplay import constants
from syncplay.messages import getMessage
import sys
import os
import itertools
import hashlib
def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
"""Retry calling the decorated function using an exponential backoff.
http://www.saltycrane.com/blog/2009/11/trying-out-retry-decorator-python/
original from: http://wiki.python.org/moin/PythonDecoratorLibrary#Retry
:param ExceptionToCheck: the exception to check. may be a tuple of
excpetions to check
:type ExceptionToCheck: Exception or tuple
:param tries: number of times to try (not retry) before giving up
:type tries: int
:param delay: initial delay between retries in seconds
:type delay: int
:param backoff: backoff multiplier e.g. value of 2 will double the delay
each retry
:type backoff: int
:param logger: logger to use. If None, print
:type logger: logging.Logger instance
"""
def deco_retry(f):
def f_retry(*args, **kwargs):
mtries, mdelay = tries, delay
try_one_last_time = True
while mtries > 1:
try:
return f(*args, **kwargs)
try_one_last_time = False
break
except ExceptionToCheck, e:
if logger:
msg = getMessage("retrying-notification").format(str(e), mdelay)
logger.warning(msg)
time.sleep(mdelay)
mtries -= 1
mdelay *= backoff
if try_one_last_time:
return f(*args, **kwargs)
return
return f_retry # true decorator
return deco_retry
def parseTime(timeStr):
regex = re.compile(constants.PARSE_TIME_REGEX)
parts = regex.match(timeStr)
if not parts:
return
parts = parts.groupdict()
time_params = {}
for (name, param) in parts.iteritems():
if param:
if name == "miliseconds":
time_params["microseconds"] = int(param) * 1000
else:
time_params[name] = int(param)
return datetime.timedelta(**time_params).total_seconds()
def formatTime(timeInSeconds, weeksAsTitles=True):
if timeInSeconds < 0:
timeInSeconds = -timeInSeconds
sign = '-'
else:
sign = ''
timeInSeconds = round(timeInSeconds)
weeks = timeInSeconds // 604800
if weeksAsTitles and weeks > 0:
title = weeks
weeks = 0
else:
title = 0
days = (timeInSeconds % 604800) // 86400
hours = (timeInSeconds % 86400) // 3600
minutes = (timeInSeconds % 3600) // 60
seconds = timeInSeconds % 60
if weeks > 0:
formattedTime = '{0:}{1:.0f}w, {2:.0f}d, {3:02.0f}:{4:02.0f}:{5:02.0f}'.format(sign, weeks, days, hours, minutes, seconds)
elif days > 0:
formattedTime = '{0:}{1:.0f}d, {2:02.0f}:{3:02.0f}:{4:02.0f}'.format(sign, days, hours, minutes, seconds)
elif hours > 0:
formattedTime = '{0:}{1:02.0f}:{2:02.0f}:{3:02.0f}'.format(sign, hours, minutes, seconds)
else:
formattedTime = '{0:}{1:02.0f}:{2:02.0f}'.format(sign, minutes, seconds)
if title > 0:
formattedTime = "{0:} (Title {1:.0f})".format(formattedTime, title)
return formattedTime
def findWorkingDir():
frozen = getattr(sys, 'frozen', '')
if not frozen:
path = os.path.dirname(os.path.dirname(__file__))
elif frozen in ('dll', 'console_exe', 'windows_exe'):
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
else:
path = ""
return path
def limitedPowerset(s, minLength):
return itertools.chain.from_iterable(itertools.combinations(s, r) for r in xrange(len(s), minLength, -1))
def blackholeStdoutForFrozenWindow():
if getattr(sys, 'frozen', '') == "windows_exe":
class Stderr(object):
softspace = 0
_file = None
_error = None
def write(self, text, fname='.syncplay.log'):
if self._file is None and self._error is None:
if os.name <> 'nt':
path = os.path.join(os.getenv('HOME', '.'), fname)
else:
path = os.path.join(os.getenv('APPDATA', '.'), fname)
self._file = open(path, 'a')
#TODO: Handle errors.
if self._file is not None:
self._file.write(text)
self._file.flush()
def flush(self):
if self._file is not None:
self._file.flush()
sys.stderr = Stderr()
del Stderr
class Blackhole(object):
softspace = 0
def write(self, text):
pass
def flush(self):
pass
sys.stdout = Blackhole()
del Blackhole
# Relate to file hashing / difference checking:
def stripfilename(filename):
return re.sub(constants.FILENAME_STRIP_REGEX, "", filename)
def hashFilename(filename):
return hashlib.sha256(stripfilename(filename).encode('utf-8')).hexdigest()[:12]
def hashFilesize(size):
return hashlib.sha256(str(size)).hexdigest()[:12]
def sameHashed(string1raw, string1hashed, string2raw, string2hashed):
if string1raw == string2raw:
return True
elif string1raw == string2hashed:
return True
elif string1hashed == string2raw:
return True
elif string1hashed == string2hashed:
return True
def sameFilename (filename1, filename2):
if filename1 == constants.PRIVACY_HIDDENFILENAME or filename2 == constants.PRIVACY_HIDDENFILENAME:
return True
elif sameHashed(stripfilename(filename1), hashFilename(filename1), stripfilename(filename2), hashFilename(filename2)):
return True
else:
return False
def sameFilesize (filesize1, filesize2):
if filesize1 == 0 or filesize2 == 0:
return True
elif sameHashed(filesize1, hashFilesize(filesize1), filesize2, hashFilesize(filesize2)):
return True
else:
return False
def sameFileduration (duration1, duration2):
if abs(round(duration1) - round(duration2)) < constants.DIFFFERENT_DURATION_THRESHOLD:
return True
else:
return False