Coverage for torxtools/ctxtools.py: 78%

27 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-18 01:02 +0000

1""" 

2Utilities for with-statement contexts 

3""" 

4# pylint: disable=invalid-name 

5import contextlib 

6import sys 

7 

8 

9class suppress_traceback(contextlib.AbstractContextManager): 

10 """ 

11 Context handler to suppress tracebacks and pretty print an error. 

12 

13 In case exception is KeyboardInterrupt, then the error is suppressed. 

14 No assumption, error or normal exit, is made for why Ctrl-C was used. 

15 

16 Example 

17 ------- 

18 

19 .. code-block:: 

20 

21 if __name__ == "__main__": 

22 with suppress_traceback(): 

23 main() 

24 """ 

25 

26 def __init__(self, keyboard_exitcode=1, system_exitcode=1, error_exitcode=1): 

27 self.keyboard_exitcode = keyboard_exitcode 

28 self.system_exitcode = system_exitcode 

29 self.error_exitcode = error_exitcode 

30 

31 def __exit__(self, exctype, excinst, _exctb): 

32 if exctype is None: 

33 return True 

34 

35 if issubclass(exctype, KeyboardInterrupt): 

36 # exit code could be success or error, it all depends on if it's the 

37 # normal way of quitting the app, so eat the exception by default. 

38 sys.exit(self.keyboard_exitcode) 

39 

40 if issubclass(exctype, SystemExit): 

41 # sys.exit was called with an exit-code, then re-raise with value 

42 with contextlib.suppress(ValueError, TypeError): 

43 code = int(excinst.code) 

44 sys.exit(code) 

45 

46 # sys.exit was called with an message, print and re-reaise with error 

47 print(excinst, file=sys.stderr) 

48 sys.exit(self.system_exitcode) 

49 

50 print(f"error: {excinst}", file=sys.stderr) 

51 sys.exit(self.error_exitcode) 

52 

53 

54class suppress(contextlib.suppress, contextlib.ContextDecorator): 

55 """ 

56 A version of contextlib.suppress with decorator support. 

57 

58 Example 

59 ------- 

60 

61 .. code-block:: 

62 

63 @contextlib.suppress(ValueError) 

64 def foobar(): 

65 ... 

66 """ 

67 

68 

69class reraise_from_none(contextlib.suppress, contextlib.ContextDecorator): 

70 """ 

71 Similar to contextlib.suppress, but with decorator support, and that 

72 re-raises exception from None instead of hiding it. 

73 

74 Example 

75 ------- 

76 

77 .. code-block:: 

78 

79 @contextlib.reraise_from_none(ValueError) 

80 def foobar(): 

81 ... 

82 """ 

83 

84 def __exit__(self, exctype, excinst, _exctb): 

85 if exctype is None: 

86 return 

87 if issubclass(exctype, self._exceptions): 

88 raise excinst from None