Coverage for src/debputy/lsp/ref_models/deb822_reference_parse_models.py: 84%

92 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2025-01-27 13:59 +0000

1import re 

2import sys 

3from enum import Enum 

4from typing import ( 

5 NotRequired, 

6 List, 

7 Any, 

8 Optional, 

9 Iterable, 

10 Literal, 

11 Dict, 

12) 

13 

14from debputy.lsp.vendoring._deb822_repro import ( 

15 LIST_SPACE_SEPARATED_INTERPRETATION, 

16 LIST_COMMA_SEPARATED_INTERPRETATION, 

17) 

18from debputy.lsp.vendoring._deb822_repro.parsing import ( 

19 LIST_UPLOADERS_INTERPRETATION, 

20 Deb822ParsedTokenList, 

21 Interpretation, 

22 _parse_whitespace_list_value, 

23 Deb822ParsedValueElement, 

24 _parsed_value_render_factory, 

25 ListInterpretation, 

26) 

27from debputy.lsp.vendoring._deb822_repro.tokens import ( 

28 Deb822SpaceSeparatorToken, 

29 _value_line_tokenizer, 

30 _RE_WHITESPACE_SEPARATED_WORD_LIST, 

31 Deb822ValueToken, 

32 Deb822Token, 

33) 

34from debputy.manifest_parser.declarative_parser import ParserGenerator 

35from debputy.manifest_parser.tagging_types import DebputyParsedContent 

36 

37_DEB822_REFERENCE_DATA_PARSER_GENERATOR = ParserGenerator() 

38 

39# FIXME: should go into python3-debian 

40_RE_COMMA = re.compile("([^,]*),([^,]*)") 

41 

42UsageHint = Literal["rare",] 

43 

44 

45@_value_line_tokenizer 

46def comma_or_space_split_tokenizer(v: str) -> Iterable[Deb822Token]: 

47 assert "\n" not in v 

48 for match in _RE_WHITESPACE_SEPARATED_WORD_LIST.finditer(v): 

49 space_before, word, space_after = match.groups() 

50 if space_before: 50 ↛ 52line 50 didn't jump to line 52 because the condition on line 50 was always true

51 yield Deb822SpaceSeparatorToken(sys.intern(space_before)) 

52 if "," in word: 52 ↛ 53line 52 didn't jump to line 53 because the condition on line 52 was never true

53 for m in _RE_COMMA.finditer(word): 

54 word_before, word_after = m.groups() 

55 if word_before: 

56 yield Deb822ValueToken(word_before) 

57 # ... not quite a whitespace, but it is too much pain to make it a non-whitespace token. 

58 yield Deb822SpaceSeparatorToken(",") 

59 if word_after: 

60 yield Deb822ValueToken(word_after) 

61 else: 

62 yield Deb822ValueToken(word) 

63 if space_after: 63 ↛ 64line 63 didn't jump to line 64 because the condition on line 63 was never true

64 yield Deb822SpaceSeparatorToken(sys.intern(space_after)) 

65 

66 

67# FIXME: should go into python3-debian 

68LIST_COMMA_OR_SPACE_SEPARATED_INTERPRETATION = ListInterpretation( 68 ↛ exitline 68 didn't jump to the function exit

69 comma_or_space_split_tokenizer, 

70 _parse_whitespace_list_value, 

71 Deb822ParsedValueElement, 

72 Deb822SpaceSeparatorToken, 

73 lambda: Deb822SpaceSeparatorToken(","), 

74 _parsed_value_render_factory, 

75) 

76 

77_KEY2FIELD_VALUE_CLASS: Dict[str, "FieldValueClass"] 

78 

79 

80class FieldValueClass(Enum): 

81 SINGLE_VALUE = "single-value", LIST_SPACE_SEPARATED_INTERPRETATION 

82 SPACE_SEPARATED_LIST = "space-separated-list", LIST_SPACE_SEPARATED_INTERPRETATION 

83 BUILD_PROFILES_LIST = "build-profiles-list", None # TODO 

84 COMMA_SEPARATED_LIST = "comma-separated-list", LIST_COMMA_SEPARATED_INTERPRETATION 

85 COMMA_SEPARATED_EMAIL_LIST = ( 

86 "comma-separated-email-list", 

87 LIST_UPLOADERS_INTERPRETATION, 

88 ) 

89 COMMA_OR_SPACE_SEPARATED_LIST = ( 

90 "comma-or-space-separated-list", 

91 LIST_COMMA_OR_SPACE_SEPARATED_INTERPRETATION, 

92 ) 

93 FREE_TEXT_FIELD = "free-text", None 

94 DEP5_FILE_LIST = "dep5-file-list", LIST_SPACE_SEPARATED_INTERPRETATION 

95 

96 @classmethod 

97 def from_key(cls, key: str) -> "FieldValueClass": 

98 return _KEY2FIELD_VALUE_CLASS[key] 

99 

100 @property 

101 def key(self) -> str: 

102 return self.value[0] 

103 

104 def interpreter(self) -> Optional[Interpretation[Deb822ParsedTokenList[Any, Any]]]: 

105 return self.value[1] 

106 

107 

108# TODO: Have the parser generator support enums better than this hack. 

109FieldValueType = Literal[tuple(x.key for x in FieldValueClass)] 

110_KEY2FIELD_VALUE_CLASS = {x.key: x for x in FieldValueClass} 

111 

112 

113class Documentation(DebputyParsedContent): 

114 synopsis: NotRequired[str] 

115 long_description: NotRequired[str] 

116 uris: NotRequired[List[str]] 

117 

118 

119class DCtrlSubstvar(DebputyParsedContent): 

120 name: str 

121 defined_by: str 

122 dh_sequence: NotRequired[str] 

123 documentation: NotRequired[Documentation] 

124 

125 

126class DctrlSubstvarsReferenceData(DebputyParsedContent): 

127 substvars: List[DCtrlSubstvar] 

128 

129 

130class StaticValue(DebputyParsedContent): 

131 value: str 

132 documentation: NotRequired[Documentation] 

133 sort_key: NotRequired[str] 

134 usage_hint: NotRequired[UsageHint] 

135 

136 

137class Deb822Field(DebputyParsedContent): 

138 canonical_name: str 

139 field_value_type: FieldValueType 

140 unknown_value_authority: NotRequired[str] 

141 missing_field_authority: NotRequired[str] 

142 default_value: NotRequired[str] 

143 usage_hint: NotRequired[UsageHint] 

144 documentation: NotRequired[Documentation] 

145 values: NotRequired[List[StaticValue]] 

146 replaced_by: NotRequired[str] 

147 is_obsolete_without_replacement: NotRequired[Literal[True]] 

148 spellcheck_value: NotRequired[Literal[True]] 

149 

150 

151class StanzaType(DebputyParsedContent): 

152 stanza_name: str 

153 fields: List[Deb822Field] 

154 

155 

156class ReferenceVariable(DebputyParsedContent): 

157 name: str 

158 fallback: str 

159 

160 

161class ReferenceDefinition(DebputyParsedContent): 

162 variables: NotRequired[List[ReferenceVariable]] 

163 

164 

165class Deb822ReferenceData(DebputyParsedContent): 

166 definitions: NotRequired[ReferenceDefinition] 

167 stanza_types: List[StanzaType] 

168 

169 

170DEB822_REFERENCE_DATA_PARSER = _DEB822_REFERENCE_DATA_PARSER_GENERATOR.generate_parser( 

171 Deb822ReferenceData 

172) 

173 

174 

175DCTRL_SUBSTVARS_REFERENCE_DATA_PARSER = ( 

176 _DEB822_REFERENCE_DATA_PARSER_GENERATOR.generate_parser(DctrlSubstvarsReferenceData) 

177)