]> crepu.dev Git - config.git/blame - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/flake8/options/manager.py
Actualizado el Readme
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / flake8 / options / manager.py
CommitLineData
53e6db90
DC
1"""Option handling and Option management logic."""
2from __future__ import annotations
3
4import argparse
5import enum
6import functools
7import logging
8from typing import Any
9from typing import Callable
10from typing import Sequence
11
12from flake8 import utils
13from flake8.plugins.finder import Plugins
14
15LOG = logging.getLogger(__name__)
16
17# represent a singleton of "not passed arguments".
18# an enum is chosen to trick mypy
19_ARG = enum.Enum("_ARG", "NO")
20
21
22def _flake8_normalize(
23 value: str,
24 *args: str,
25 comma_separated_list: bool = False,
26 normalize_paths: bool = False,
27) -> str | list[str]:
28 ret: str | list[str] = value
29 if comma_separated_list and isinstance(ret, str):
30 ret = utils.parse_comma_separated_list(value)
31
32 if normalize_paths:
33 if isinstance(ret, str):
34 ret = utils.normalize_path(ret, *args)
35 else:
36 ret = utils.normalize_paths(ret, *args)
37
38 return ret
39
40
41class Option:
42 """Our wrapper around an argparse argument parsers to add features."""
43
44 def __init__(
45 self,
46 short_option_name: str | _ARG = _ARG.NO,
47 long_option_name: str | _ARG = _ARG.NO,
48 # Options below are taken from argparse.ArgumentParser.add_argument
49 action: str | type[argparse.Action] | _ARG = _ARG.NO,
50 default: Any | _ARG = _ARG.NO,
51 type: Callable[..., Any] | _ARG = _ARG.NO,
52 dest: str | _ARG = _ARG.NO,
53 nargs: int | str | _ARG = _ARG.NO,
54 const: Any | _ARG = _ARG.NO,
55 choices: Sequence[Any] | _ARG = _ARG.NO,
56 help: str | _ARG = _ARG.NO,
57 metavar: str | _ARG = _ARG.NO,
58 required: bool | _ARG = _ARG.NO,
59 # Options below here are specific to Flake8
60 parse_from_config: bool = False,
61 comma_separated_list: bool = False,
62 normalize_paths: bool = False,
63 ) -> None:
64 """Initialize an Option instance.
65
66 The following are all passed directly through to argparse.
67
68 :param short_option_name:
69 The short name of the option (e.g., ``-x``). This will be the
70 first argument passed to ``ArgumentParser.add_argument``
71 :param long_option_name:
72 The long name of the option (e.g., ``--xtra-long-option``). This
73 will be the second argument passed to
74 ``ArgumentParser.add_argument``
75 :param default:
76 Default value of the option.
77 :param dest:
78 Attribute name to store parsed option value as.
79 :param nargs:
80 Number of arguments to parse for this option.
81 :param const:
82 Constant value to store on a common destination. Usually used in
83 conjunction with ``action="store_const"``.
84 :param choices:
85 Possible values for the option.
86 :param help:
87 Help text displayed in the usage information.
88 :param metavar:
89 Name to use instead of the long option name for help text.
90 :param required:
91 Whether this option is required or not.
92
93 The following options may be passed directly through to :mod:`argparse`
94 but may need some massaging.
95
96 :param type:
97 A callable to normalize the type (as is the case in
98 :mod:`argparse`).
99 :param action:
100 Any action allowed by :mod:`argparse`.
101
102 The following parameters are for Flake8's option handling alone.
103
104 :param parse_from_config:
105 Whether or not this option should be parsed out of config files.
106 :param comma_separated_list:
107 Whether the option is a comma separated list when parsing from a
108 config file.
109 :param normalize_paths:
110 Whether the option is expecting a path or list of paths and should
111 attempt to normalize the paths to absolute paths.
112 """
113 if (
114 long_option_name is _ARG.NO
115 and short_option_name is not _ARG.NO
116 and short_option_name.startswith("--")
117 ):
118 short_option_name, long_option_name = _ARG.NO, short_option_name
119
120 # flake8 special type normalization
121 if comma_separated_list or normalize_paths:
122 type = functools.partial(
123 _flake8_normalize,
124 comma_separated_list=comma_separated_list,
125 normalize_paths=normalize_paths,
126 )
127
128 self.short_option_name = short_option_name
129 self.long_option_name = long_option_name
130 self.option_args = [
131 x
132 for x in (short_option_name, long_option_name)
133 if x is not _ARG.NO
134 ]
135 self.action = action
136 self.default = default
137 self.type = type
138 self.dest = dest
139 self.nargs = nargs
140 self.const = const
141 self.choices = choices
142 self.help = help
143 self.metavar = metavar
144 self.required = required
145 self.option_kwargs: dict[str, Any | _ARG] = {
146 "action": self.action,
147 "default": self.default,
148 "type": self.type,
149 "dest": self.dest,
150 "nargs": self.nargs,
151 "const": self.const,
152 "choices": self.choices,
153 "help": self.help,
154 "metavar": self.metavar,
155 "required": self.required,
156 }
157
158 # Set our custom attributes
159 self.parse_from_config = parse_from_config
160 self.comma_separated_list = comma_separated_list
161 self.normalize_paths = normalize_paths
162
163 self.config_name: str | None = None
164 if parse_from_config:
165 if long_option_name is _ARG.NO:
166 raise ValueError(
167 "When specifying parse_from_config=True, "
168 "a long_option_name must also be specified."
169 )
170 self.config_name = long_option_name[2:].replace("-", "_")
171
172 self._opt = None
173
174 @property
175 def filtered_option_kwargs(self) -> dict[str, Any]:
176 """Return any actually-specified arguments."""
177 return {
178 k: v for k, v in self.option_kwargs.items() if v is not _ARG.NO
179 }
180
181 def __repr__(self) -> str: # noqa: D105
182 parts = []
183 for arg in self.option_args:
184 parts.append(arg)
185 for k, v in self.filtered_option_kwargs.items():
186 parts.append(f"{k}={v!r}")
187 return f"Option({', '.join(parts)})"
188
189 def normalize(self, value: Any, *normalize_args: str) -> Any:
190 """Normalize the value based on the option configuration."""
191 if self.comma_separated_list and isinstance(value, str):
192 value = utils.parse_comma_separated_list(value)
193
194 if self.normalize_paths:
195 if isinstance(value, list):
196 value = utils.normalize_paths(value, *normalize_args)
197 else:
198 value = utils.normalize_path(value, *normalize_args)
199
200 return value
201
202 def to_argparse(self) -> tuple[list[str], dict[str, Any]]:
203 """Convert a Flake8 Option to argparse ``add_argument`` arguments."""
204 return self.option_args, self.filtered_option_kwargs
205
206
207class OptionManager:
208 """Manage Options and OptionParser while adding post-processing."""
209
210 def __init__(
211 self,
212 *,
213 version: str,
214 plugin_versions: str,
215 parents: list[argparse.ArgumentParser],
216 formatter_names: list[str],
217 ) -> None:
218 """Initialize an instance of an OptionManager."""
219 self.formatter_names = formatter_names
220 self.parser = argparse.ArgumentParser(
221 prog="flake8",
222 usage="%(prog)s [options] file file ...",
223 parents=parents,
224 epilog=f"Installed plugins: {plugin_versions}",
225 )
226 self.parser.add_argument(
227 "--version",
228 action="version",
229 version=(
230 f"{version} ({plugin_versions}) "
231 f"{utils.get_python_version()}"
232 ),
233 )
234 self.parser.add_argument("filenames", nargs="*", metavar="filename")
235
236 self.config_options_dict: dict[str, Option] = {}
237 self.options: list[Option] = []
238 self.extended_default_ignore: list[str] = []
239 self.extended_default_select: list[str] = []
240
241 self._current_group: argparse._ArgumentGroup | None = None
242
243 # TODO: maybe make this a free function to reduce api surface area
244 def register_plugins(self, plugins: Plugins) -> None:
245 """Register the plugin options (if needed)."""
246 groups: dict[str, argparse._ArgumentGroup] = {}
247
248 def _set_group(name: str) -> None:
249 try:
250 self._current_group = groups[name]
251 except KeyError:
252 group = self.parser.add_argument_group(name)
253 self._current_group = groups[name] = group
254
255 for loaded in plugins.all_plugins():
256 add_options = getattr(loaded.obj, "add_options", None)
257 if add_options:
258 _set_group(loaded.plugin.package)
259 add_options(self)
260
261 if loaded.plugin.entry_point.group == "flake8.extension":
262 self.extend_default_select([loaded.entry_name])
263
264 # isn't strictly necessary, but seems cleaner
265 self._current_group = None
266
267 def add_option(self, *args: Any, **kwargs: Any) -> None:
268 """Create and register a new option.
269
270 See parameters for :class:`~flake8.options.manager.Option` for
271 acceptable arguments to this method.
272
273 .. note::
274
275 ``short_option_name`` and ``long_option_name`` may be specified
276 positionally as they are with argparse normally.
277 """
278 option = Option(*args, **kwargs)
279 option_args, option_kwargs = option.to_argparse()
280 if self._current_group is not None:
281 self._current_group.add_argument(*option_args, **option_kwargs)
282 else:
283 self.parser.add_argument(*option_args, **option_kwargs)
284 self.options.append(option)
285 if option.parse_from_config:
286 name = option.config_name
287 assert name is not None
288 self.config_options_dict[name] = option
289 self.config_options_dict[name.replace("_", "-")] = option
290 LOG.debug('Registered option "%s".', option)
291
292 def extend_default_ignore(self, error_codes: Sequence[str]) -> None:
293 """Extend the default ignore list with the error codes provided.
294
295 :param error_codes:
296 List of strings that are the error/warning codes with which to
297 extend the default ignore list.
298 """
299 LOG.debug("Extending default ignore list with %r", error_codes)
300 self.extended_default_ignore.extend(error_codes)
301
302 def extend_default_select(self, error_codes: Sequence[str]) -> None:
303 """Extend the default select list with the error codes provided.
304
305 :param error_codes:
306 List of strings that are the error/warning codes with which
307 to extend the default select list.
308 """
309 LOG.debug("Extending default select list with %r", error_codes)
310 self.extended_default_select.extend(error_codes)
311
312 def parse_args(
313 self,
314 args: Sequence[str] | None = None,
315 values: argparse.Namespace | None = None,
316 ) -> argparse.Namespace:
317 """Proxy to calling the OptionParser's parse_args method."""
318 if values:
319 self.parser.set_defaults(**vars(values))
320 return self.parser.parse_args(args)