Source code for flix.utils
"""
Module `utils` provides some compatibility utilities for both Python 2 and 3.
.. data:: PY3
Indicates if running on Python 3+ (:class:`bool`).
.. data:: string_types
Available string types for current Python version (:class:`type`).
.. function:: str_to_bytes(s)
Convert string to bytes. This is a noop for Python 2.
.. function:: bytes_to_str(s)
Convert bytes to string. This is a noop for Python 2.
.. function:: assure_unicode(s)
Convert string to unicode if necessary. This is a noop for Python 3.
.. function:: assure_str(s)
Convert unicode to string if necessary. This is a noop for Python 3.
"""
import logging
import re
import sys
from concurrent.futures import ThreadPoolExecutor
PY3 = sys.version_info.major >= 3
RESERVED_PATH_CHARS_RE = re.compile(r'[<>:"/\\|?*%+]')
if PY3:
string_types = str
def str_to_bytes(s):
return s.encode()
def bytes_to_str(b):
return b.decode()
def assure_unicode(s):
return s
def assure_str(s):
return s
else:
# noinspection PyUnresolvedReferences
string_types = basestring # noqa
[docs]
def str_to_bytes(s):
return s
[docs]
def bytes_to_str(b):
return b
[docs]
def assure_unicode(s):
if isinstance(s, str):
# noinspection PyUnresolvedReferences
s = s.decode("utf-8")
return s
[docs]
def assure_str(s):
# noinspection PyUnresolvedReferences
if isinstance(s, unicode): # noqa
s = s.encode("utf-8")
return s
def get_data(func, iterable, threads=5, **kwargs):
"""
Apply `func` to each element in `iterable`, collecting the results in a generator that is returned.
:param func: The function to apply to each element.
:param iterable: Iterable containing `func` inputs.
:param threads: Number of workers.
:keyword yield_exceptions: Yield (or not) exceptions. If not set, exceptions are raised.
"""
yield_exceptions = kwargs.get("yield_exceptions")
with ThreadPoolExecutor(threads) as pool:
for result in [pool.submit(func, args) for args in iterable]:
try:
yield result.result()
except Exception as e:
if yield_exceptions is None:
raise e
if yield_exceptions:
yield e
else:
logging.error("Failed while performing get_data: %s", e, exc_info=True)
def make_legal_name(name):
"""
Create a legal file name from the passed string.
:param name: The name to make legal.
:return: The legal file name.
:rtype: str
"""
return RESERVED_PATH_CHARS_RE.sub("", name)
def make_hash(obj, hash_func=hash):
"""
Return the hash value for the given object.
:param obj: The object which to calculate the hash.
:param hash_func: Hash function to use.
:return: The hash value.
"""
if isinstance(obj, (tuple, list)):
return hash_func((type(obj), tuple(make_hash(e, hash_func) for e in obj)))
elif isinstance(obj, (set, frozenset)):
return hash_func((type(obj), tuple(make_hash(e, hash_func) for e in sorted(obj))))
elif isinstance(obj, dict):
return hash_func((type(obj), tuple((k, make_hash(obj[k]), hash_func) for k in sorted(obj))))
return hash_func(obj)
def args_rep(*args, **kwargs):
"""
Return the representation of args and kwargs.
:return: The representation string.
:rtype: str
"""
a = ", ".join(repr(a) for a in args)
k = ", ".join(k + "=" + repr(kwargs[k]) for k in sorted(kwargs))
s = ", " if a and k else ""
return "(" + a + s + k + ")"