Coverage for torxtools/ctxtools.py: 78%

27 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-20 22:02 +0000

1""" 

2Utilities for with-statement contexts 

3""" 

4 

5# pylint: disable=invalid-name 

6import contextlib 

7import sys 

8 

9 

10class suppress_traceback(contextlib.AbstractContextManager): 

11 """ 

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

13 

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

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

16 

17 Example 

18 ------- 

19 

20 .. code-block:: 

21 

22 if __name__ == "__main__": 

23 with suppress_traceback(): 

24 main() 

25 """ 

26 

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

28 self.keyboard_exitcode = keyboard_exitcode 

29 self.system_exitcode = system_exitcode 

30 self.error_exitcode = error_exitcode 

31 

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

33 if exctype is None: 

34 return True 

35 

36 if issubclass(exctype, KeyboardInterrupt): 

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

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

39 sys.exit(self.keyboard_exitcode) 

40 

41 if issubclass(exctype, SystemExit): 

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

43 with contextlib.suppress(ValueError, TypeError): 

44 code = int(excinst.code) 

45 sys.exit(code) 

46 

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

48 print(excinst, file=sys.stderr) 

49 sys.exit(self.system_exitcode) 

50 

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

52 sys.exit(self.error_exitcode) 

53 

54 

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

56 """ 

57 A version of contextlib.suppress with decorator support. 

58 

59 Example 

60 ------- 

61 

62 .. code-block:: 

63 

64 @contextlib.suppress(ValueError) 

65 def foobar(): 

66 ... 

67 """ 

68 

69 

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

71 """ 

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

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

74 

75 Example 

76 ------- 

77 

78 .. code-block:: 

79 

80 @contextlib.reraise_from_none(ValueError) 

81 def foobar(): 

82 ... 

83 """ 

84 

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

86 if exctype is None: 

87 return 

88 if issubclass(exctype, self._exceptions): 

89 raise excinst from None