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
« prev ^ index » next coverage.py v7.8.2, created at 2026-04-19 20:37 +0000
1import textwrap
2from typing import Optional, Type, Any
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
21class BoolDebputyParsedContent(DebputyParsedContent):
22 content: bool
25TT = type[T]
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 )
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.
72 Consider the following example:
73 ```debian/control
74 Source: foo
76 Package: foo
77 # Here is a comment with a typu.
78 Description: Also a mistkae here
79 ```
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.
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
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 )
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
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 )
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
167DEBPUTY_CONFIG_PARSER = _debputy_config_parser()
169del _debputy_config_parser
170del _config_value
171del _add_sub_object_parser
172del _debputy_self_check_config_parser