Coverage for src/debputy/lsp/config/parser.py: 90%

50 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-09-07 09:27 +0000

1import textwrap 

2from typing import Optional, Type, Any 

3 

4from debputy.manifest_parser.declarative_parser import ( 

5 ParserGenerator, 

6 DeclarativeNonMappingInputParser, 

7) 

8from debputy.manifest_parser.tagging_types import DebputyParsedContent 

9from debputy.plugin.api import reference_documentation 

10from debputy.plugin.api.impl import plugin_metadata_for_debputys_own_plugin 

11from debputy.plugin.api.impl_types import ( 

12 DispatchingObjectParser, 

13 DebputyPluginMetadata, 

14 DeclarativeInputParser, 

15) 

16from debputy.plugin.api.spec import ParserDocumentation 

17from debputy.util import T, _error 

18from .config_options import ALL_DEBPUTY_CONFIG_OPTIONS 

19 

20 

21class BoolDebputyParsedContent(DebputyParsedContent): 

22 content: bool 

23 

24 

25TT = Type[T] 

26 

27 

28def _debputy_config_parser() -> DispatchingObjectParser: 

29 pg = ParserGenerator() 

30 plugin_metadata = plugin_metadata_for_debputys_own_plugin() 

31 root_parser = pg.add_object_parser( 

32 "<ROOT>", 

33 unknown_keys_diagnostic_severity=None, 

34 allow_unknown_keys=True, 

35 ) 

36 diagnostics_object_parser = _add_sub_object_parser( 

37 pg, 

38 root_parser, 

39 "diagnostics", 

40 plugin_metadata, 

41 parser_documentation=reference_documentation( 

42 title="Diagnostics related settings (`diagnostics`)", 

43 description=textwrap.dedent( 

44 """\ 

45 Configurations related to diagnostics. 

46 """ 

47 ), 

48 ), 

49 ) 

50 

51 spellchecking_diagnostics = _add_sub_object_parser( 

52 pg, 

53 diagnostics_object_parser, 

54 "spellchecking", 

55 plugin_metadata, 

56 parser_documentation=reference_documentation( 

57 title="Spellchecking related diagnostics settings (`spellchecking`)", 

58 description=textwrap.dedent( 

59 """\ 

60 Settings related to spellchecking diagnostics 

61 """ 

62 ), 

63 ), 

64 ) 

65 _config_value( 

66 pg, 

67 spellchecking_diagnostics, 

68 "spellcheck-comments", 

69 bool, 

70 plugin_metadata, 

71 inline_reference_documentation=reference_documentation( 

72 title="Whether to spellcheck comments (`spellcheck-comments`)", 

73 description=textwrap.dedent( 

74 """\ 

75 Define whether `debputy` should spellcheck syntactical comments. 

76 

77 Consider the following example: 

78 ```debian/control 

79 Source: foo 

80 

81 Package: foo 

82 # Here is a comment with a typu. 

83 Description: Also a mistkae here 

84 ``` 

85 

86 This option affects whether `typu` in the above example will be 

87 reported provided textual spellchecking is enabled. The other typo 

88 (`mistkae`) is unaffected by this option, since it is not inside 

89 a syntactical comment. 

90 

91 When this option is present and set to `false`, then syntactical comments 

92 are never spellchecked. 

93 """ 

94 ), 

95 ), 

96 ) 

97 _debputy_self_check_config_parser(root_parser) 

98 return root_parser 

99 

100 

101def _debputy_self_check_config_parser(root_parser: DispatchingObjectParser) -> None: 

102 for config_option in ALL_DEBPUTY_CONFIG_OPTIONS: 

103 parser: DeclarativeInputParser[Any] = root_parser 

104 for part in config_option.config_name.split("."): 

105 if isinstance(parser, DispatchingObjectParser): 105 ↛ 108line 105 didn't jump to line 108 because the condition on line 105 was always true

106 parser = parser.parser_for(part).parser 

107 else: 

108 _error( 

109 f"Unknown parser for {config_option.config_name} at {part}: {parser}" 

110 ) 

111 if not isinstance(parser, DeclarativeNonMappingInputParser): 111 ↛ 112line 111 didn't jump to line 112 because the condition on line 111 was never true

112 _error( 

113 f"Expecting {config_option.config_name} to resolve to a DeclarativeNonMappingInputParser, got: {parser}" 

114 ) 

115 if parser.alt_form_parser.attribute_type != config_option.value_type: 115 ↛ 116line 115 didn't jump to line 116 because the condition on line 115 was never true

116 _error( 

117 f"Expecting {config_option.config_name} to be of type {config_option.value_type}, but parser suggest it is {parser.alt_form_parser.attribute_type}" 

118 ) 

119 

120 

121def _config_value( 

122 pg: ParserGenerator, 

123 parent_parser: DispatchingObjectParser, 

124 path: str, 

125 value_type: TT, 

126 plugin_metadata: DebputyPluginMetadata, 

127 *, 

128 inline_reference_documentation: Optional[ParserDocumentation] = None, 

129) -> None: 

130 class DebputyParsedContentWrapper(DebputyParsedContent): 

131 content: value_type # type: ignore 

132 

133 parser = pg.generate_parser( 

134 DebputyParsedContentWrapper, 

135 source_content=value_type, 

136 inline_reference_documentation=inline_reference_documentation, 

137 ) 

138 parent_parser.register_parser( 

139 path, 

140 parser, 

141 lambda k, pf, ap, pc: pf["content"], 

142 plugin_metadata, 

143 ) 

144 

145 

146def _add_sub_object_parser( 

147 pg: ParserGenerator, 

148 parent_parser: DispatchingObjectParser, 

149 path: str, 

150 plugin_metadata: DebputyPluginMetadata, 

151 *, 

152 parser_documentation: Optional[ParserDocumentation] = None, 

153) -> DispatchingObjectParser: 

154 if parent_parser.manifest_attribute_path_template == "<ROOT>": 

155 full_path = path 

156 else: 

157 full_path = f"{parent_parser.manifest_attribute_path_template}.{path}" 

158 child_parser = pg.add_object_parser( 

159 full_path, 

160 unknown_keys_diagnostic_severity=None, 

161 parser_documentation=parser_documentation, 

162 allow_unknown_keys=True, 

163 ) 

164 parent_parser.register_parser( 

165 path, 

166 child_parser, 

167 lambda k, pf, ap, pc: pf, 

168 plugin_metadata, 

169 ) 

170 return child_parser 

171 

172 

173DEBPUTY_CONFIG_PARSER = _debputy_config_parser() 

174 

175del _debputy_config_parser 

176del _config_value 

177del _add_sub_object_parser 

178del _debputy_self_check_config_parser