Source code for Hellas.Pella
"""mostly dict list and file related functions and classes named after
the ancient city of `Pella <https://en.wikipedia.org/wiki/Pella>`_
"""
from copy import copy
import signal
from base64 import b64encode
from random import random
from Hellas.Sparta import Error
[docs]class ErrorFileTooBig(Error):
pass
# file operations -------------------------------------------------------------
[docs]def file_to_base64(path_or_obj, max_mb=None):
"""converts contents of a file to base64 encoding
:param str_or_object path_or_obj: fool pathname string for a file or a file like object that supports read
:param int max_mb: maximum number in MegaBytes to accept
:param float lon2: longitude of second place (decimal degrees)
:raises ErrorFileTooBig: if file contents > max_mb (see :class:`ErrorFileTooBig`)
:raises IOError: if file path can't be found (Also possible other exceptions depending on file_object)
"""
def read_file():
with open(path_or_obj, 'rb') as fin:
return fin.read()
if not hasattr(path_or_obj, 'read'):
rt = read_file()
else:
rt = path_or_obj.read()
if max_mb:
len_mb = len(rt) / (10024.0 * 1000)
if len_mb > max_mb:
raise ErrorFileTooBig("File is too big ({.2f} MBytes)" (len_mb))
return b64encode(rt)
# dictionary operations -------------------------------------------------------
[docs]def dict_copy(a_dict, exclude_keys_lst=[], exclude_values_lst=[]):
"""a **SALLOW** copy of a dict that excludes items in exclude_keys_lst and exclude_values_lst
useful for copying locals() etc..
:param dict a_dict: dictionary to be copied
:param list exclude_keys_lst: a list or tuple of keys to exclude
:param list exclude_values_lst: a list or tuple of values to exclude
.. Warning:: remember it is NOT a deep copy
"""
return dict([copy(i) for i in list(a_dict.items())
if i[0] not in exclude_keys_lst and i[1] not in exclude_values_lst])
[docs]def dict_clip(a_dict, inlude_keys_lst=[]):
"""returns a new dict with keys not in included in inlude_keys_lst clipped off"""
return dict([[i[0], i[1]] for i in list(a_dict.items()) if i[0] in inlude_keys_lst])
# list operations -------------------------------------------------------------
[docs]def list_randomize(lst):
"""returns list in random order"""
return sorted(lst, key=lambda x: random())
[docs]def list_pp(ll, separator='|', header_line=True, autonumber=True):
"""pretty print list of lists ll"""
if autonumber:
for cnt, i in enumerate(ll):
i.insert(0, cnt if cnt > 0 or not header_line else '#')
def lenlst(l):
return [len(str(i)) for i in l]
lst_len = [lenlst(i) for i in ll]
lst_rot = zip(*lst_len[::-1])
lst_len = [max(i) for i in lst_rot]
frmt = separator + separator.join(["{!s:"+str(i)+"}" for i in lst_len]) + separator
if header_line:
header_line = '-' * len(frmt.format(*ll[0]))
for cnt, l in enumerate(ll):
if cnt < 2 and header_line:
print(header_line)
print(frmt.format(*l))
if header_line:
print(header_line)
return lst_len
# signal -----------------------------------------------------------------------
[docs]def signal_terminate(on_terminate):
"""a common case program termination signal"""
for i in [signal.SIGINT, signal.SIGQUIT, signal.SIGUSR1, signal.SIGUSR2, signal.SIGTERM]:
signal.signal(i, on_terminate)
# classes -----------------------------------------------------------------------
[docs]class Base62(object):
"""unsigned integer coder class codes to and from base 62, useful for compressing integer values
.. Warning:: any encoded values can only be decoded by this class
:Example:
>>> b62 = Base62()
>>> vl = 2 ** 24
16777216
>>> b62.encode(vl)
'18OWG'
>>> b62.decode('18OWG')
16777216
"""
symbols = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
numeric_symbols = symbols[:10]
def __repr__(self):
return "<base62: (%s)>" % (self.symbols)
@staticmethod
def _code(number, from_digits, to_digits):
x = 0
len_from_digits = len(from_digits)
len_to_digits = len(to_digits)
for ch in str(number):
x = x * len_from_digits + from_digits.index(ch)
if x == 0:
res = to_digits[0]
else:
res = ''
while x > 0:
digit = x % len_to_digits
res = to_digits[digit] + res
x = int(x // len_to_digits)
return res
@classmethod
[docs] def encode(cls, number):
return cls._code(number, cls.numeric_symbols, cls.symbols)
@classmethod
[docs] def decode(cls, number):
return int(cls._code(number, cls.symbols, cls.numeric_symbols))