Coverage for app/venv/lib/python3.14/site-packages/weblate/checks/parser.py: 43%

52 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-07 07:15 +0000

1# Copyright © Michal Čihař <michal@weblate.org> 

2# 

3# SPDX-License-Identifier: GPL-3.0-or-later 

4 

5from __future__ import annotations 

6 

7import re 

8import threading 

9from typing import TYPE_CHECKING 

10 

11from pyparsing import Optional, QuotedString, Regex, ZeroOrMore 

12 

13if TYPE_CHECKING: 13 ↛ 14line 13 didn't jump to line 14 because the condition on line 13 was never true

14 from pyparsing import ParserElement 

15 

16 

17def single_value_flag(func, validation=None): 

18 def parse_values(val): 

19 if not val: 

20 msg = "Missing required parameter" 

21 raise ValueError(msg) 

22 if len(val) > 1: 

23 msg = "Too many parameters" 

24 raise ValueError(msg) 

25 result = func(val[0]) 

26 if validation is not None: 

27 validation(result) 

28 return result 

29 

30 return parse_values 

31 

32 

33def length_validation(length: int): 

34 def validate_length(val) -> None: 

35 if len(val) > length: 

36 msg = "String too long" 

37 raise ValueError(msg) 

38 

39 return validate_length 

40 

41 

42def multi_value_flag( 

43 func, minimum: int = 1, maximum: int | None = None, modulo: int | None = None 

44): 

45 def parse_values(val): 

46 if modulo and len(val) % modulo != 0: 

47 msg = "Number of parameter is not even" 

48 raise ValueError(msg) 

49 if minimum and len(val) < minimum: 

50 msg = "Missing required parameter" 

51 raise ValueError(msg) 

52 if maximum and len(val) > maximum: 

53 msg = "Too many parameters" 

54 raise ValueError(msg) 

55 return [func(x) for x in val] 

56 

57 return parse_values 

58 

59 

60class RawQuotedString(QuotedString): 

61 def __init__(self, quote_char: str, esc_char: str = "\\") -> None: 

62 super().__init__(quote_char, esc_char=esc_char, convert_whitespace_escapes=True) 

63 # unlike the QuotedString this replaces only escaped quotes and not all chars 

64 self.unquote_scan_re = re.compile( 

65 rf"({'|'.join(re.escape(k) for k in self.ws_map)})|({re.escape(self.esc_char)}[{re.escape(quote_char)}{re.escape(esc_char)}])|(\n|.)", 

66 flags=self.re_flags, 

67 ) 

68 

69 

70SYNTAXCHARS = {",", ":", '"', "'", "\\"} 

71 

72 

73def get_flags_parser() -> ParserElement: 

74 flag_name = Regex(r"""[^,:"' \r\n\t]([^,:"']*[^,:"' \r\n\t])?""") 

75 

76 regex_string = "r" + RawQuotedString('"') 

77 

78 flag_param = Optional( 

79 regex_string | flag_name | RawQuotedString("'") | RawQuotedString('"') 

80 ) 

81 

82 flag = flag_name + ZeroOrMore(":" + flag_param) 

83 

84 return Optional(flag) + ZeroOrMore("," + Optional(flag)) 

85 

86 

87FLAGS_PARSER: ParserElement = get_flags_parser() 

88FLAGS_PARSER_LOCK = threading.Lock()