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

50 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2026-04-19 20:37 +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 Configurations related to diagnostics. 

45 """), 

46 ), 

47 ) 

48 

49 spellchecking_diagnostics = _add_sub_object_parser( 

50 pg, 

51 diagnostics_object_parser, 

52 "spellchecking", 

53 plugin_metadata, 

54 parser_documentation=reference_documentation( 

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

56 description=textwrap.dedent("""\ 

57 Settings related to spellchecking diagnostics 

58 """), 

59 ), 

60 ) 

61 _config_value( 

62 pg, 

63 spellchecking_diagnostics, 

64 "spellcheck-comments", 

65 bool, 

66 plugin_metadata, 

67 inline_reference_documentation=reference_documentation( 

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

69 description=textwrap.dedent("""\ 

70 Define whether `debputy` should spellcheck syntactical comments. 

71 

72 Consider the following example: 

73 ```debian/control 

74 Source: foo 

75 

76 Package: foo 

77 # Here is a comment with a typu. 

78 Description: Also a mistkae here 

79 ``` 

80 

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

82 reported provided textual spellchecking is enabled. The other typo 

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

84 a syntactical comment. 

85 

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

87 are never spellchecked. 

88 """), 

89 ), 

90 ) 

91 _debputy_self_check_config_parser(root_parser) 

92 return root_parser 

93 

94 

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

96 for config_option in ALL_DEBPUTY_CONFIG_OPTIONS: 

97 parser: DeclarativeInputParser[Any] = root_parser 

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

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

100 parser = parser.parser_for(part).parser 

101 else: 

102 _error( 

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

104 ) 

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

106 _error( 

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

108 ) 

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

110 _error( 

111 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}" 

112 ) 

113 

114 

115def _config_value( 

116 pg: ParserGenerator, 

117 parent_parser: DispatchingObjectParser, 

118 path: str, 

119 value_type: TT, 

120 plugin_metadata: DebputyPluginMetadata, 

121 *, 

122 inline_reference_documentation: ParserDocumentation | None = None, 

123) -> None: 

124 class DebputyParsedContentWrapper(DebputyParsedContent): 

125 content: value_type # type: ignore 

126 

127 parser = pg.generate_parser( 

128 DebputyParsedContentWrapper, 

129 source_content=value_type, 

130 inline_reference_documentation=inline_reference_documentation, 

131 ) 

132 parent_parser.register_parser( 

133 path, 

134 parser, 

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

136 plugin_metadata, 

137 ) 

138 

139 

140def _add_sub_object_parser( 

141 pg: ParserGenerator, 

142 parent_parser: DispatchingObjectParser, 

143 path: str, 

144 plugin_metadata: DebputyPluginMetadata, 

145 *, 

146 parser_documentation: ParserDocumentation | None = None, 

147) -> DispatchingObjectParser: 

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

149 full_path = path 

150 else: 

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

152 child_parser = pg.add_object_parser( 

153 full_path, 

154 unknown_keys_diagnostic_severity=None, 

155 parser_documentation=parser_documentation, 

156 allow_unknown_keys=True, 

157 ) 

158 parent_parser.register_parser( 

159 path, 

160 child_parser, 

161 lambda k, pf, ap, pc: pf, 

162 plugin_metadata, 

163 ) 

164 return child_parser 

165 

166 

167DEBPUTY_CONFIG_PARSER = _debputy_config_parser() 

168 

169del _debputy_config_parser 

170del _config_value 

171del _add_sub_object_parser 

172del _debputy_self_check_config_parser