# coding: utf-8
import argparse
import datetime
import re
from typing import Any, Iterable, List
from ._colorings import toBLUE, toGREEN, toRED
from ._exceptions import KeyError
NoneType = type(None)
[docs]def handleKeyError(lst: List[Any], **kwargs):
"""Check whether all ``kwargs.values()`` in the ``lst``.
Args:
lst (List[Any]) : candidates.
kwargs (dict) : ``key`` is the varname that is easy to understand when an error occurs
Examples:
>>> from wed.utils import handleKeyError
>>> handleKeyError(lst=range(3), val=1)
>>> handleKeyError(lst=range(3), val=100)
KeyError: Please choose the argment val from ['0', '1', '2']. you chose 100
>>> handleKeyError(lst=range(3), val1=1, val2=2)
>>> handleKeyError(lst=range(3), val1=1, val2=100)
KeyError: Please choose the argment val2 from ['0', '1', '2']. you chose 100
Raise:
KeyError: If ``kwargs.values()`` not in the ``lst``
"""
for k, v in kwargs.items():
if v not in lst:
lst = ", ".join([f"'{toGREEN(e)}'" for e in lst])
raise KeyError(
f"Please choose the argment {toBLUE(k)} from [{lst}]. you chose {toRED(v)}"
)
[docs]def class2str(class_: object) -> str:
"""Convert class to str.
Args:
class_ (object): class object
Returns:
str : Class name.
Examples:
>>> from wed.utils import class2str
>>> class2str(str)
'str'
>>> class2str(tuple)
'tuple'
"""
return re.sub(r"<class '(.*?)'>", r"\1", str(class_))
[docs]def handleTypeError(types: List = [Any], **kwargs):
"""Check whether all types of ``kwargs.values()`` match any of ``types``.
Args:
types (List[Any]) : Candidate types.
kwargs (dict) : ``key`` is the varname that is easy to understand when an error occurs
Examples:
>>> from wed.utils import handleTypeError
>>> handleTypeError(types=[str], val="foo")
>>> handleTypeError(types=[str, int], val=1)
>>> handleTypeError(types=[str, int], val=1.)
TypeError: val must be one of ['str', 'int'], not float
>>> handleTypeError(types=[str], val1="foo", val2="bar")
>>> handleTypeError(types=[str, int], val1="foo", val2=1.)
TypeError: val2 must be one of ['str', 'int'], not float
Raise:
TypeError: If the types of ``kwargs.values()`` are none of the ``types``
"""
types = tuple([NoneType if e is None else e for e in types])
for k, v in kwargs.items():
if not isinstance(v, types):
str_true_types = ", ".join([f"'{toGREEN(class2str(t))}'" for t in types])
srt_false_type = class2str(type(v))
if len(types) == 1:
err_msg = f"must be {str_true_types}"
else:
err_msg = f"must be one of [{str_true_types}]"
raise TypeError(f"{toBLUE(k)} {err_msg}, not {toRED(srt_false_type)}")
[docs]def str_strip(string: str) -> str:
"""Convert all consecutive whitespace characters to `' '` (half-width whitespace), then return a copy of the string with leading and trailing whitespace removed.
Args:
string (str) : string
Returns:
str : A copy of the string with leading and trailing whitespace removed
Example:
>>> from wed.utils import str_strip
>>> str_strip(" hoge ")
'hoge'
>>> str_strip(" ho ge ")
'ho ge'
>>> str_strip(" ho g e")
'ho g e'
"""
return re.sub(pattern=r"[\s ]+", repl=" ", string=str(string)).strip()
[docs]def now_str(tz=None, fmt="%Y-%m-%d@%H.%M.%S"):
"""Returns new datetime string representing current time local to ``tz`` under the control of an explicit format string.
Args:
tz (datetime.timezone) : Timezone object. If no ``tz`` is specified, uses local timezone.
fmt (str) : format string. See `Python Documentation <https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes>`_
Returns:
str : A datetime string.
Example:
>>> from wed.utils import now_str
>>> now_str()
'2020-09-14@22.31.17'
>>>now_str(fmt="%A, %d. %B %Y %I:%M%p")
Monday, 14. September 2020 10:31PM'
>>> now_str(tz=datetime.timezone.utc)
'2020-09-14@13.31.17'
"""
return datetime.datetime.now(tz=tz).strftime(fmt)
[docs]def flatten_dual(lst: List[List[Any]]) -> List[Any]:
"""Flatten double list.
Args:
lst (List[List[Any]]): Dual list.
Returns:
List[Any] : Flattened single list.
Example:
>>> from pycharmers.utils import flatten_dual
>>> flatten_dual([[1,2,3],[4,5,6]])
[1, 2, 3, 4, 5, 6]
>>> flatten_dual([[[1,2,3]],[4,5,6]])
[[1, 2, 3], 4, 5, 6]
>>> flatten_dual(flatten_dual([[[1,2,3]],[4,5,6]]))
TypeError: 'int' object is not iterable
Raise:
TypeError: If list is not a dual list.
"""
return [element for sublist in lst for element in sublist]
[docs]def verbose2print(prefix: str = "", verbose: bool = True):
"""Create a simple print function based on verbose
Args:
prefix (str, optional) : Prefix Text for
verbose (bool, optional) : Whether to print or not. Defaults to ``True``.
Returns:
function : Print function
Examples:
>>> from wed.utils import verbose2print
>>> print_verbose = verbose2print(verbose=True)
>>> print_non_verbose = verbose2print(verbose=False)
>>> print_verbose("Hello, world.")
Hello, world.
>>> print_non_verbose = verbose2print("Hello, world.")
"""
if verbose:
if len(prefix) > 0:
return lambda *args, **kwargs: print(prefix, *args, **kwargs)
else:
return lambda *args, **kwargs: print(*args, **kwargs)
else:
return lambda *args, **kwargs: None
[docs]def pretty_3quote(*value, indent: int = 0):
"""pretty 3 quote string.
Args:
indent (int, optional) : If indent is a non-negative integer, then multiple lines will be pretty-printed with that indent level. Defaults to ``0``.
Examples:
>>> from wed.utils import pretty_3quote
>>> print(*pretty_3quote(\"\"\"
... When I was 17, I read a quote that went something like:
... “If you live each day as if it was your last, someday you’ll most certainly be right.”
... It made an impression on me, and since then, for the past 33 years,
>>> \"\"\"))
When I was 17, I read a quote that went something like:
“If you live each day as if it was your last, someday you’ll most certainly be right.”
It made an impression on me, and since then, for the past 33 years,
"""
return [
re.sub(pattern=r"\n\s+", repl=r"\n" + r" " * indent, string=val).strip("\n")
for val in value
]
[docs]class Cycler:
def __init__(
self,
sizes: Iterable[int],
diffs: Iterable[int],
periods: Iterable[int],
shifts: Iterable[int],
):
self.sizes, self.sizes_len = sizes, len(sizes)
self.diffs, self.diffs_len = diffs, len(diffs)
self.periods, self.periods_len = periods, len(periods)
self.shifts, self.shifts_len = shifts, len(shifts)
[docs] def get(self, pos: int, idx: int):
size = self.sizes[idx % self.sizes_len]
diff = self.diffs[idx % self.diffs_len]
period = self.periods[idx % self.periods_len]
shift = self.shifts[idx % self.shifts_len]
half_period = period // 2
return size + diff * abs(half_period - (pos + shift) % period) / half_period