Coverage for visailu/cli.py: 96.00%

66 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-05 19:49:28 +00:00

1"""Command line interface for quiz (Finnish: visailu) data operations.""" 

2 

3import logging 

4import pathlib 

5 

6import typer 

7 

8from visailu import APP_NAME, QUIET, __version__ as APP_VERSION, log 

9from visailu.publish import publish_path 

10from visailu.validate import validate_path 

11from visailu.verify import verify_path 

12 

13app = typer.Typer( 

14 add_completion=False, 

15 context_settings={'help_option_names': ['-h', '--help']}, 

16 no_args_is_help=True, 

17) 

18 

19DocumentPath = typer.Option( 

20 '', 

21 '-f', 

22 '--file', 

23 help='File path to read model from', 

24) 

25Verbosity = typer.Option( 

26 False, 

27 '-v', 

28 '--verbose', 

29 help='Verbose output (default is False)', 

30) 

31Strictness = typer.Option( 

32 False, 

33 '-s', 

34 '--strict', 

35 help='Ouput noisy warnings on console (default is False)', 

36) 

37OutputPath = typer.Option( 

38 '', 

39 '-o', 

40 '--output-path', 

41 help='Path to output unambiguous content to - like when ejecting a template', 

42) 

43 

44 

45@app.callback(invoke_without_command=True) 

46def callback( 

47 version: bool = typer.Option( 

48 False, 

49 '-V', 

50 '--version', 

51 help='Display the application version and exit', 

52 is_eager=True, 

53 ) 

54) -> None: 

55 """ 

56 Quiz (Finnish: visailu) data operations. 

57 """ 

58 if version: 

59 typer.echo(f'{APP_NAME} version {APP_VERSION}') 

60 raise typer.Exit() 

61 

62 

63def _verify_call_vector( 

64 doc_path: str, doc_path_pos: str, verbose: bool, strict: bool 

65) -> tuple[int, str, str, dict[str, bool]]: 

66 """DRY""" 

67 doc = doc_path.strip() 

68 if not doc and doc_path_pos: 

69 doc = doc_path_pos 

70 if not doc: 

71 return 2, 'Document path required', '', {} 

72 

73 doc_path_path = pathlib.Path(doc) 

74 if doc_path_path.exists(): 

75 if not doc_path_path.is_file(): 75 ↛ 76line 75 didn't jump to line 76, because the condition on line 75 was never true

76 return 2, f'requested model file path at ({doc}) is not a file', '', {} 

77 else: 

78 return 2, f'requested model file path at ({doc}) does not exist', '', {} 

79 

80 options = { 

81 'quiet': QUIET and not verbose and not strict, 

82 'strict': strict, 

83 'verbose': verbose, 

84 } 

85 if verbose: 85 ↛ 86line 85 didn't jump to line 86, because the condition on line 85 was never true

86 logging.getLogger().setLevel(logging.DEBUG) 

87 return 0, '', doc, options 

88 

89 

90@app.command('verify') 

91def verify_cmd( # noqa 

92 doc_path_pos: str = typer.Argument(''), 

93 doc_path: str = DocumentPath, 

94 verbose: bool = Verbosity, 

95 strict: bool = Strictness, 

96) -> int: 

97 """ 

98 Verify the model data against YAML syntax. 

99 """ 

100 code, message, path, options = _verify_call_vector(doc_path, doc_path_pos, verbose, strict) 

101 if code: 

102 log.error(message) 

103 raise typer.Exit(code=code) 

104 

105 code, message, data = verify_path(path, options=options) 

106 if code != 0: 

107 log.error(message) 

108 

109 raise typer.Exit(code=code) 

110 

111 

112@app.command('validate') 

113def validate_cmd( # noqa 

114 doc_path_pos: str = typer.Argument(''), 

115 doc_path: str = DocumentPath, 

116 verbose: bool = Verbosity, 

117 strict: bool = Strictness, 

118) -> int: 

119 """ 

120 Validate the YAML data against the model. 

121 """ 

122 code, message, path, options = _verify_call_vector(doc_path, doc_path_pos, verbose, strict) 

123 if code: 

124 log.error(message) 

125 raise typer.Exit(code=code) 

126 

127 code, message, data = validate_path(path, options=options) 

128 if code != 0: 

129 log.error(f'path {path} {message}') 

130 

131 raise typer.Exit(code=code) 

132 

133 

134@app.command('publish') 

135def publish_cmd( # noqa 

136 doc_path_pos: str = typer.Argument(''), 

137 doc_path: str = DocumentPath, 

138 verbose: bool = Verbosity, 

139 strict: bool = Strictness, 

140) -> int: 

141 """ 

142 Publish the model data in simplified JSON syntax. 

143 """ 

144 code, message, path, options = _verify_call_vector(doc_path, doc_path_pos, verbose, strict) 

145 if code: 

146 log.error(message) 

147 raise typer.Exit(code=code) 

148 

149 code, message, data = publish_path(path, options=options) 

150 if code != 0: 

151 log.error(f'path {path} {message}') 

152 else: 

153 log.info(message) 

154 

155 raise typer.Exit(code=code) 

156 

157 

158@app.command('version') 

159def app_version() -> None: 

160 """ 

161 Display the application version and exit. 

162 """ 

163 callback(True)