Coverage for src/pydal2sql/typer_support.py: 100%

33 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-04-22 14:51 +0200

1""" 

2Cli-specific support. 

3""" 

4 

5import contextlib 

6import functools 

7import os 

8import sys 

9from pathlib import Path 

10from typing import Any, Never 

11 

12import dotenv 

13import rich 

14import typer 

15from pydal2sql_core.state import ( 

16 DEFAULT_VERBOSITY, 

17 AbstractConfig, 

18 ApplicationState, 

19 Config, 

20 DB_Types, 

21 DynamicEnum, 

22 MaybeConfig, 

23 ReprEnumMeta, 

24 Verbosity, 

25 Verbosity_Comparable, 

26 create_enum_from_literal, 

27 get_pydal2sql_config, 

28 state, 

29) 

30from su6 import find_project_root 

31from su6.core import ( 

32 EXIT_CODE_ERROR, 

33 EXIT_CODE_SUCCESS, 

34 T_Command, 

35 T_Inner_Wrapper, 

36 T_Outer_Wrapper, 

37) 

38 

39__all__ = [ 

40 "DEFAULT_VERBOSITY", 

41 "IS_DEBUG", 

42 "AbstractConfig", 

43 "ApplicationState", 

44 "Config", 

45 "DB_Types", 

46 "DynamicEnum", 

47 "MaybeConfig", 

48 "ReprEnumMeta", 

49 "Verbosity", 

50 "Verbosity_Comparable", 

51 "create_enum_from_literal", 

52 "get_pydal2sql_config", 

53 "is_debug", 

54 "state", 

55 "with_exit_code", 

56] 

57 

58 

59def with_exit_code(hide_tb: bool = True) -> T_Outer_Wrapper: 

60 """ 

61 Convert the return value of an app.command (bool or int) to an typer Exit with return code, \ 

62 Unless the return value is Falsey, in which case the default exit happens (with exit code 0 indicating success). 

63 

64 Usage: 

65 > @app.command() 

66 > @with_exit_code() 

67 def some_command(): ... 

68 

69 When calling a command from a different command, _suppress=True can be added to not raise an Exit exception. 

70 

71 See Also: 

72 github.com:trialandsuccess/su6-checker 

73 """ 

74 

75 def outer_wrapper(func: T_Command) -> T_Inner_Wrapper: 

76 @functools.wraps(func) 

77 def inner_wrapper(*args: Any, **kwargs: Any) -> Never: 

78 try: 

79 result = func(*args, **kwargs) 

80 except Exception as e: 

81 result = EXIT_CODE_ERROR 

82 if hide_tb: 

83 rich.print(f"[red]{e}[/red]", file=sys.stderr) 

84 else: # pragma: no cover 

85 raise e 

86 finally: 

87 sys.stdout.flush() 

88 sys.stderr.flush() 

89 

90 if result is True: 

91 # assume no issue then 

92 result = EXIT_CODE_SUCCESS 

93 elif result is False: 

94 result = EXIT_CODE_ERROR 

95 

96 raise typer.Exit(code=int(result or 0)) 

97 

98 return inner_wrapper 

99 

100 return outer_wrapper 

101 

102 

103def _is_debug() -> bool: # pragma: no cover 

104 folder, _ = find_project_root((os.getcwd(),)) 

105 if not folder: 

106 folder = Path(os.getcwd()) 

107 dotenv.load_dotenv(folder / ".env") 

108 

109 return os.getenv("IS_DEBUG") == "1" 

110 

111 

112def is_debug() -> bool: # pragma: no cover 

113 """ 

114 Returns whether IS_DEBUG = 1 in the .env. 

115 """ 

116 with contextlib.suppress(Exception): 

117 return _is_debug() 

118 return False 

119 

120 

121IS_DEBUG = is_debug()