# -*- coding: utf-8 -*- import pytimeparse, os from datetime import datetime, timedelta from collections import OrderedDict from .log import * _int_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] def _strip(s_, throw=True, log_level=ERR): s = s_.strip() if len(s) != 0: return s msg = f'Tried to strip empty string "{s_}" to int' if throw: raise Exception(msg) slog(log_level, msg) return None def cast_str_to_timedelta(s_: str, throw=True, log_level=DEBUG): # export s = _strip(s_, throw=throw, log_level=log_level) try: return (True, timedelta(seconds=pytimeparse.parse(s_))) except Exception as e: msg = f'Could not convert string "{s_}" to time ({e})' if throw: raise Exception(msg) slog(log_level, msg) return (False, None) def cast_str_to_int(s_: str, throw=True, log_level=DEBUG): # export s = _strip(s_, throw=throw, log_level=log_level) if s[0] == '-': s = s[1:] for c in s: if not c in _int_chars: break else: return (True, int(s_)) msg = f'Could not convert string "{s_}" to int' if throw: raise Exception(msg) slog(log_level, msg) return (False, None) def cast_str_to_bool(s_: str, throw=True, log_level=DEBUG): # export s = _strip(s_, throw=throw, log_level=log_level).lower() if s in ['true', 'yes', '1']: return (True, True) if s in ['false', 'no', '0']: return (True, False) msg = f'Could not convert string "{s_}" to bool' if throw: raise Exception(msg) slog(log_level, msg) return (False, None) _str_cast_functions = OrderedDict({ bool: cast_str_to_bool, int: cast_str_to_int, timedelta: cast_str_to_timedelta }) def guess_type(s: str, default=None, log_level=DEBUG, throw=False): # export if s is None: raise Exception('None string passed to guess_type()') for tp, func in _str_cast_functions.items(): try: success, value = func(s, log_level=OFF, throw=False) if success: return tp except: continue msg = f'Failed to guess type of string "{s}"' if throw: raise Exception(msg) slog(log_level, msg) return default def from_str(s: str, target_type=None, default_type=None, throw=True, log_level=WARNING, caller=None): # export if target_type is None: target_type = guess_type(s, default_type) if target_type is None: msg = f'Could not deduce type to cast to from string "{s}"' if throw: raise Exception(msg) slog(log_level, msg) return None result = _str_cast_functions[target_type](s, throw=throw, log_level=log_level) if result[0]: return result[1] msg = f'Failed to cast string "{s}" to type {target_type}' if throw: raise Exception(msg) slog(log_level, msg) return None def from_env(key: str, default=None, target_type=None, default_type=None, throw=True, log_level=WARNING, caller=None): # export val = os.getenv(key) if val is None: return default if target_type is None and default is not None: target_type = type(default) return from_str(val, target_type=target_type, default_type=default_type, throw=throw, log_level=log_level, caller=caller) # deprecated name def cast_str(s: str, target_type=None, default_type=None, throw=True, log_level=WARNING, caller=None): return from_str(s, target_type=target_type, default_type=None, throw=True, log_level=WARNING, caller=None)