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
« 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
5from __future__ import annotations
7import copy
8import optparse # pylint: disable=deprecated-module
9import pathlib
10import re
11import warnings
12from re import Pattern
14from pylint import utils
17# pylint: disable=unused-argument
18def _csv_validator(_, name, value):
19 return utils._check_csv(value)
22# pylint: disable=unused-argument
23def _regexp_validator(_, name, value):
24 if hasattr(value, "pattern"):
25 return value
26 return re.compile(value)
29# pylint: disable=unused-argument
30def _regexp_csv_validator(_, name, value):
31 return [_regexp_validator(_, name, val) for val in _csv_validator(_, name, value)]
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
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
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))
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
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)
87def _multiple_choices_validating_option(opt, name, value): # pragma: no cover # Unused
88 return _multiple_choice_validator(opt.choices, name, value)
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
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}
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
137def _validate(value, optdict, name=""):
138 """Return a validated value for an option according to its type.
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)
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
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
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 )
202 optparse.Option.CHECK_METHODS[2] = _check_choice # type: ignore[index]
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)