Coretex
error_handling.py
1 # Copyright (C) 2023 Coretex LLC
2 
3 # This file is part of Coretex.ai
4 
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
14 
15 # You should have received a copy of the GNU Affero General Public License
16 # along with this program. If not, see <https://www.gnu.org/licenses/>.
17 
18 from typing import Any, Callable, TypeVar, Generic, Union, NoReturn, Type, Tuple
19 from typing_extensions import ParamSpec
20 
21 import logging
22 
23 
24 ParamsType = ParamSpec("ParamsType")
25 ReturnType = TypeVar("ReturnType")
26 ExceptionType = TypeVar("ExceptionType", bound = BaseException)
27 
28 
29 class Success(Generic[ReturnType]):
30 
31  __match_args__ = ("value",)
32 
33  def __init__(self, value: ReturnType) -> None:
34  self.value = value
35 
36  def unwrap(self) -> ReturnType:
37  return self.value
38 
39 
40 class Error(Generic[ReturnType]):
41 
42  __match_args__ = ("exception",)
43 
44  def __init__(self, exception: ExceptionType) -> None:
45  self.exception = exception
46 
47  def unwrap(self) -> NoReturn:
48  raise self.exception
49 
50 
51 class Throws(Generic[ExceptionType]):
52 
53  def __init__(self, exceptions: Tuple[Type[ExceptionType], ...]) -> None:
54  self.exceptions = exceptions
55 
56  def __call__(self, function: Callable[ParamsType, ReturnType]) -> Callable[ParamsType, Union[Success[ReturnType], Error[ExceptionType]]]:
57  def inner(*args: Any, **kwargs: Any) -> Union[Success[ReturnType], Error]:
58  try:
59  result = function(*args, **kwargs)
60  return Success(result)
61  except KeyboardInterrupt:
62  raise
63  except BaseException as ex:
64  if len(self.exceptions) > 0 and not isinstance(ex, self.exceptions):
65  logging.warning(">> [Coretex] Received unexpected exception")
66 
67  return Error(ex)
68 
69  # Keep the original function name
70  inner.__name__ = function.__name__
71 
72  return inner