From 522d3bc5d94645cdb63abe3a9d55aac272ed573f Mon Sep 17 00:00:00 2001 From: Dima Gerasimov Date: Sat, 21 Dec 2019 10:58:45 +0000 Subject: [PATCH] Move error handling to common --- my/body/blood.py | 6 ++- my/{kython/kerror.py => error.py} | 65 ++++++++++++------------------- my/reading/polar.py | 2 +- 3 files changed, 30 insertions(+), 43 deletions(-) rename my/{kython/kerror.py => error.py} (60%) diff --git a/my/body/blood.py b/my/body/blood.py index 6f6c913..a24c3c4 100755 --- a/my/body/blood.py +++ b/my/body/blood.py @@ -4,9 +4,11 @@ from typing import Iterable, NamedTuple, Optional from itertools import chain import porg -from kython import listify +from .common import listify +from ..error import Res, echain + + from kython.org import parse_org_date -from kython.kerror import Res, echain from mycfg import paths diff --git a/my/kython/kerror.py b/my/error.py similarity index 60% rename from my/kython/kerror.py rename to my/error.py index 7484de3..721cb63 100644 --- a/my/kython/kerror.py +++ b/my/error.py @@ -1,23 +1,20 @@ -from typing import Union, TypeVar, Iterator, Callable, Iterable, List, Tuple, Type +""" +Various error handling helpers +See https://beepb00p.xyz/mypy-error-handling.html#kiss for more detail +""" + +from itertools import tee +from typing import Union, TypeVar, Iterable, List, Tuple, Type T = TypeVar('T') -E = TypeVar('E', bound=Exception) +E = TypeVar('E', bound=Exception) # TODO make covariant? ResT = Union[T, E] Res = ResT[T, Exception] -# TODO make it a bit more typed?? -def is_error(res: Res[T]) -> bool: - return isinstance(res, Exception) - - -def is_ok(res: Res[T]) -> bool: - return not is_error(res) - - def unwrap(res: Res[T]) -> T: if isinstance(res, Exception): raise res @@ -25,38 +22,26 @@ def unwrap(res: Res[T]) -> T: return res -def split_errors(l: Iterable[ResT[T, E]], ET=Exception) -> Tuple[List[T], List[E]]: - rl: List[T] = [] - el: List[E] = [] - for x in l: - if isinstance(x, ET): - el.append(x) - else: - rl.append(x) # type: ignore - return rl, el - - -def ytry(cb) -> Iterator[Exception]: - try: - cb() - except Exception as e: - yield e - - -# TODO experimental, not sure if I like it def echain(ex: E, cause: Exception) -> E: ex.__cause__ = cause - # TODO assert cause is none? - # TODO copy?? return ex - # try: - # # TODO is there a awy to get around raise from? - # raise ex from cause - # except Exception as e: - # if isinstance(e, type(ex)): - # return e - # else: - # raise e + + +def split_errors(l: Iterable[ResT[T, E]], ET: Type[E]) -> Tuple[Iterable[T], Iterable[E]]: + # TODO would be nice to have ET=Exception default? + vit, eit = tee(l) + # TODO ugh, not sure if I can reconcile type checking and runtime and convince mypy that ET and E are the same type? + values: Iterable[T] = ( + r # type: ignore[misc] + for r in vit + if not isinstance(r, ET)) + errors: Iterable[E] = ( + r + for r in eit + if isinstance(r, ET)) + # TODO would be interesting to be able to have yield statement anywehere in code + # so there are multiple 'entry points' to the return value + return (values, errors) def sort_res_by(items: Iterable[ResT], key) -> List[ResT]: diff --git a/my/reading/polar.py b/my/reading/polar.py index 9594a78..ca4c140 100755 --- a/my/reading/polar.py +++ b/my/reading/polar.py @@ -9,7 +9,7 @@ import pytz from ..common import setup_logger -from ..kython.kerror import ResT, echain, unwrap, sort_res_by +from ..error import ResT, echain, unwrap, sort_res_by from ..kython.konsume import wrap, zoom, ignore