Coverage for C:\Repos\ekr-pylint\pylint\config\option.py: 40%

97 statements  

« prev     ^ index     » next       coverage.py v6.4, created at 2022-05-24 10:21 -0500

1# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html 

2# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE 

3# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt 

4 

5from __future__ import annotations 

6 

7import copy 

8import optparse # pylint: disable=deprecated-module 

9import pathlib 

10import re 

11import warnings 

12from re import Pattern 

13 

14from pylint import utils 

15 

16 

17# pylint: disable=unused-argument 

18def _csv_validator(_, name, value): 

19 return utils._check_csv(value) 

20 

21 

22# pylint: disable=unused-argument 

23def _regexp_validator(_, name, value): 

24 if hasattr(value, "pattern"): 

25 return value 

26 return re.compile(value) 

27 

28 

29# pylint: disable=unused-argument 

30def _regexp_csv_validator(_, name, value): 

31 return [_regexp_validator(_, name, val) for val in _csv_validator(_, name, value)] 

32 

33 

34def _regexp_paths_csv_validator( 

35 _, name: str, value: str | list[Pattern[str]] 

36) -> list[Pattern[str]]: 

37 if isinstance(value, list): 

38 return value 

39 patterns = [] 

40 for val in _csv_validator(_, name, value): 

41 patterns.append( 

42 re.compile( 

43 str(pathlib.PureWindowsPath(val)).replace("\\", "\\\\") 

44 + "|" 

45 + pathlib.PureWindowsPath(val).as_posix() 

46 ) 

47 ) 

48 return patterns 

49 

50 

51def _choice_validator(choices, name, value): 

52 if value not in choices: 

53 msg = "option %s: invalid value: %r, should be in %s" 

54 raise optparse.OptionValueError(msg % (name, value, choices)) 

55 return value 

56 

57 

58def _yn_validator(opt, _, value): 

59 if isinstance(value, int): 

60 return bool(value) 

61 if isinstance(value, str): 

62 value = value.lower() 

63 if value in {"y", "yes", "true"}: 

64 return True 

65 if value in {"n", "no", "false"}: 

66 return False 

67 msg = "option %s: invalid yn value %r, should be in (y, yes, true, n, no, false)" 

68 raise optparse.OptionValueError(msg % (opt, value)) 

69 

70 

71def _multiple_choice_validator(choices, name, value): 

72 values = utils._check_csv(value) 

73 for csv_value in values: 

74 if csv_value not in choices: 

75 msg = "option %s: invalid value: %r, should be in %s" 

76 raise optparse.OptionValueError(msg % (name, csv_value, choices)) 

77 return values 

78 

79 

80def _non_empty_string_validator(opt, _, value): # pragma: no cover # Unused 

81 if not value: 

82 msg = "indent string can't be empty." 

83 raise optparse.OptionValueError(msg) 

84 return utils._unquote(value) 

85 

86 

87def _multiple_choices_validating_option(opt, name, value): # pragma: no cover # Unused 

88 return _multiple_choice_validator(opt.choices, name, value) 

89 

90 

91def _py_version_validator(_, name, value): 

92 if not isinstance(value, tuple): 

93 try: 

94 value = tuple(int(val) for val in value.split(".")) 

95 except (ValueError, AttributeError): 

96 raise optparse.OptionValueError( 

97 f"Invalid format for {name}, should be version string. E.g., '3.8'" 

98 ) from None 

99 return value 

100 

101 

102VALIDATORS = { 

103 "string": utils._unquote, 

104 "int": int, 

105 "float": float, 

106 "regexp": lambda pattern: re.compile(pattern or ""), 

107 "regexp_csv": _regexp_csv_validator, 

108 "regexp_paths_csv": _regexp_paths_csv_validator, 

109 "csv": _csv_validator, 

110 "yn": _yn_validator, 

111 "choice": lambda opt, name, value: _choice_validator(opt["choices"], name, value), 

112 "confidence": lambda opt, name, value: _multiple_choice_validator( 

113 opt["choices"], name, value 

114 ), 

115 "multiple_choice": lambda opt, name, value: _multiple_choice_validator( 

116 opt["choices"], name, value 

117 ), 

118 "non_empty_string": _non_empty_string_validator, 

119 "py_version": _py_version_validator, 

120} 

121 

122 

123def _call_validator(opttype, optdict, option, value): 

124 if opttype not in VALIDATORS: 

125 raise Exception(f'Unsupported type "{opttype}"') 

126 try: 

127 return VALIDATORS[opttype](optdict, option, value) 

128 except TypeError: 

129 try: 

130 return VALIDATORS[opttype](value) 

131 except Exception as e: 

132 raise optparse.OptionValueError( 

133 f"{option} value ({value!r}) should be of type {opttype}" 

134 ) from e 

135 

136 

137def _validate(value, optdict, name=""): 

138 """Return a validated value for an option according to its type. 

139 

140 optional argument name is only used for error message formatting 

141 """ 

142 try: 

143 _type = optdict["type"] 

144 except KeyError: 

145 return value 

146 return _call_validator(_type, optdict, name, value) 

147 

148 

149# pylint: disable=no-member 

150class Option(optparse.Option): 

151 TYPES = optparse.Option.TYPES + ( 

152 "regexp", 

153 "regexp_csv", 

154 "regexp_paths_csv", 

155 "csv", 

156 "yn", 

157 "confidence", 

158 "multiple_choice", 

159 "non_empty_string", 

160 "py_version", 

161 ) 

162 ATTRS = optparse.Option.ATTRS + ["hide", "level"] 

163 TYPE_CHECKER = copy.copy(optparse.Option.TYPE_CHECKER) 

164 TYPE_CHECKER["regexp"] = _regexp_validator 

165 TYPE_CHECKER["regexp_csv"] = _regexp_csv_validator 

166 TYPE_CHECKER["regexp_paths_csv"] = _regexp_paths_csv_validator 

167 TYPE_CHECKER["csv"] = _csv_validator 

168 TYPE_CHECKER["yn"] = _yn_validator 

169 TYPE_CHECKER["confidence"] = _multiple_choices_validating_option 

170 TYPE_CHECKER["multiple_choice"] = _multiple_choices_validating_option 

171 TYPE_CHECKER["non_empty_string"] = _non_empty_string_validator 

172 TYPE_CHECKER["py_version"] = _py_version_validator 

173 

174 def __init__(self, *opts, **attrs): 

175 # TODO: 3.0: Remove deprecated class 

176 warnings.warn( 

177 "Option has been deprecated and will be removed in pylint 3.0", 

178 DeprecationWarning, 

179 ) 

180 super().__init__(*opts, **attrs) 

181 if hasattr(self, "hide") and self.hide: 

182 self.help = optparse.SUPPRESS_HELP 

183 

184 def _check_choice(self): 

185 if self.type in {"choice", "multiple_choice", "confidence"}: 

186 if self.choices is None: 

187 raise optparse.OptionError( 

188 "must supply a list of choices for type 'choice'", self 

189 ) 

190 if not isinstance(self.choices, (tuple, list)): 

191 raise optparse.OptionError( 

192 # pylint: disable-next=consider-using-f-string 

193 "choices must be a list of strings ('%s' supplied)" 

194 % str(type(self.choices)).split("'")[1], 

195 self, 

196 ) 

197 elif self.choices is not None: 

198 raise optparse.OptionError( 

199 f"must not supply choices for type {self.type!r}", self 

200 ) 

201 

202 optparse.Option.CHECK_METHODS[2] = _check_choice # type: ignore[index] 

203 

204 def process(self, opt, value, values, parser): # pragma: no cover # Argparse 

205 if self.callback and self.callback.__module__ == "pylint.lint.run": 

206 return 1 

207 # First, convert the value(s) to the right type. Howl if any 

208 # value(s) are bogus. 

209 value = self.convert_value(opt, value) 

210 if self.type == "named": 

211 existent = getattr(values, self.dest) 

212 if existent: 

213 existent.update(value) 

214 value = existent 

215 # And then take whatever action is expected of us. 

216 # This is a separate method to make life easier for 

217 # subclasses to add new actions. 

218 return self.take_action(self.action, self.dest, opt, value, values, parser)