Source code for cryptocompsdk.general.parse

from typing import Any, Callable, List, Type, cast, TypeVar, Dict, Union

T = TypeVar("T")


[docs]class InvalidTypeException(Exception): pass
[docs]class NotNoneException(InvalidTypeException): pass
[docs]class NotIntException(InvalidTypeException): pass
[docs]class NotFloatException(InvalidTypeException): pass
[docs]class NotStrException(InvalidTypeException): pass
[docs]class NotBoolException(InvalidTypeException): pass
[docs]class NotListException(InvalidTypeException): pass
[docs]class NotTypeException(InvalidTypeException): pass
[docs]class NotDictException(InvalidTypeException): pass
[docs]class NotNAException(InvalidTypeException): pass
[docs]class CouldNotParseResponseException(Exception):
[docs] def __init__(self, exceptions: List[Exception], x: Any): self.exceptions = exceptions self.x = x super().__init__(self.exceptions_str)
@property def exceptions_str(self) -> str: out_str = f'Could not parse {self.x} across multiple parsers. Got errors:\n' for exc in self.exceptions: out_str += f'{str(type(exc))}: {exc}\n' return out_str
[docs]def from_na(x: Any) -> None: if not isinstance(x, str) or x not in ('N/A', 'NaN'): raise NotNAException(x) return None
[docs]def from_int(x: Any) -> int: if isinstance(x, int) and not isinstance(x, bool): return x raise NotIntException(x)
[docs]def from_none(x: Any) -> Any: if x is not None: raise NotNoneException(x) return x
[docs]def from_union(fs, x): excs = [] for f in fs: try: return f(x) except InvalidTypeException as e: excs.append(e) raise CouldNotParseResponseException(excs, x)
[docs]def from_float(x: Any) -> float: if isinstance(x, (float, int)) and not isinstance(x, bool): return float(x) raise NotFloatException(x)
[docs]def from_str(x: Any) -> str: if isinstance(x, str): return x raise NotStrException(x)
[docs]def to_float(x: Any) -> float: if isinstance(x, float): return x raise NotFloatException(x)
[docs]def from_bool(x: Any) -> bool: if isinstance(x, bool): return x raise NotBoolException(x)
[docs]def from_list(f: Callable[[Any], T], x: Any) -> List[T]: if isinstance(x, list): return [f(y) for y in x] raise NotListException(x)
[docs]def from_int_or_str(x: Any) -> Union[str, int]: try: return int(from_str(x)) except ValueError: return from_str(x)
[docs]def from_stringified_bool(x: str) -> bool: if x == "true": return True if x == "false": return False raise NotStrException(x)
[docs]def from_str_number(x: Any) -> Union[int, float]: x = from_str(x) x = x.replace(',', '') # strip thousands separators x = x.replace(' ', '').replace('\u200b', '') # strip white spacve # Some numbers are coming with . as thousands separator, while others use it as decimal. Try to detect # where it is actually a thousands separator and remove it if x.count('.') > 1 or (x.count('.') == 1 and x.endswith('0')): x = x.replace('.', '') try: num = float(x) except ValueError: raise NotFloatException(x) # Got float, need to check if actually int if int(num) == num: return int(num) # Not int, return as float return num
[docs]def to_class(c: Type[T], x: Any) -> dict: assert isinstance(x, c) return cast(Any, x).to_dict()
[docs]def is_type(t: Type[T], x: Any) -> T: if not isinstance(x, t): raise NotTypeException(f'{x} is not type {t}') return x
[docs]def from_dict(f: Callable[[Any], T], x: Any) -> Dict[str, T]: if not isinstance(x, dict): raise NotDictException(x) return { k: f(v) for (k, v) in x.items() }
[docs]def from_plain_dict(x: dict) -> dict: if not isinstance(x, dict): raise NotDictException(x) return x