]> crepu.dev Git - config.git/blame - djavu-asus/emacs/elpy/rpc-venv/lib/python3.11/site-packages/flake8/options/config.py
Reorganización de directorios
[config.git] / djavu-asus / emacs / elpy / rpc-venv / lib / python3.11 / site-packages / flake8 / options / config.py
CommitLineData
53e6db90
DC
1"""Config handling logic for Flake8."""
2from __future__ import annotations
3
4import configparser
5import logging
6import os.path
7from typing import Any
8
9from flake8 import exceptions
10from flake8.defaults import VALID_CODE_PREFIX
11from flake8.options.manager import OptionManager
12
13LOG = logging.getLogger(__name__)
14
15
16def _stat_key(s: str) -> tuple[int, int]:
17 # same as what's used by samefile / samestat
18 st = os.stat(s)
19 return st.st_ino, st.st_dev
20
21
22def _find_config_file(path: str) -> str | None:
23 # on windows if the homedir isn't detected this returns back `~`
24 home = os.path.expanduser("~")
25 try:
26 home_stat = _stat_key(home) if home != "~" else None
27 except OSError: # FileNotFoundError / PermissionError / etc.
28 home_stat = None
29
30 dir_stat = _stat_key(path)
31 while True:
32 for candidate in ("setup.cfg", "tox.ini", ".flake8"):
33 cfg = configparser.RawConfigParser()
34 cfg_path = os.path.join(path, candidate)
35 try:
36 cfg.read(cfg_path, encoding="UTF-8")
37 except (UnicodeDecodeError, configparser.ParsingError) as e:
38 LOG.warning("ignoring unparseable config %s: %s", cfg_path, e)
39 else:
40 # only consider it a config if it contains flake8 sections
41 if "flake8" in cfg or "flake8:local-plugins" in cfg:
42 return cfg_path
43
44 new_path = os.path.dirname(path)
45 new_dir_stat = _stat_key(new_path)
46 if new_dir_stat == dir_stat or new_dir_stat == home_stat:
47 break
48 else:
49 path = new_path
50 dir_stat = new_dir_stat
51
52 # did not find any configuration file
53 return None
54
55
56def load_config(
57 config: str | None,
58 extra: list[str],
59 *,
60 isolated: bool = False,
61) -> tuple[configparser.RawConfigParser, str]:
62 """Load the configuration given the user options.
63
64 - in ``isolated`` mode, return an empty configuration
65 - if a config file is given in ``config`` use that, otherwise attempt to
66 discover a configuration using ``tox.ini`` / ``setup.cfg`` / ``.flake8``
67 - finally, load any ``extra`` configuration files
68 """
69 pwd = os.path.abspath(".")
70
71 if isolated:
72 return configparser.RawConfigParser(), pwd
73
74 if config is None:
75 config = _find_config_file(pwd)
76
77 cfg = configparser.RawConfigParser()
78 if config is not None:
79 if not cfg.read(config, encoding="UTF-8"):
80 raise exceptions.ExecutionError(
81 f"The specified config file does not exist: {config}"
82 )
83 cfg_dir = os.path.dirname(config)
84 else:
85 cfg_dir = pwd
86
87 # TODO: remove this and replace it with configuration modifying plugins
88 # read the additional configs afterwards
89 for filename in extra:
90 if not cfg.read(filename, encoding="UTF-8"):
91 raise exceptions.ExecutionError(
92 f"The specified config file does not exist: {filename}"
93 )
94
95 return cfg, cfg_dir
96
97
98def parse_config(
99 option_manager: OptionManager,
100 cfg: configparser.RawConfigParser,
101 cfg_dir: str,
102) -> dict[str, Any]:
103 """Parse and normalize the typed configuration options."""
104 if "flake8" not in cfg:
105 return {}
106
107 config_dict = {}
108
109 for option_name in cfg["flake8"]:
110 option = option_manager.config_options_dict.get(option_name)
111 if option is None:
112 LOG.debug('Option "%s" is not registered. Ignoring.', option_name)
113 continue
114
115 # Use the appropriate method to parse the config value
116 value: Any
117 if option.type is int or option.action == "count":
118 value = cfg.getint("flake8", option_name)
119 elif option.action in {"store_true", "store_false"}:
120 value = cfg.getboolean("flake8", option_name)
121 else:
122 value = cfg.get("flake8", option_name)
123
124 LOG.debug('Option "%s" returned value: %r', option_name, value)
125
126 final_value = option.normalize(value, cfg_dir)
127
128 if option_name in {"ignore", "extend-ignore"}:
129 for error_code in final_value:
130 if not VALID_CODE_PREFIX.match(error_code):
131 raise ValueError(
132 f"Error code {error_code!r} "
133 f"supplied to {option_name!r} option "
134 f"does not match {VALID_CODE_PREFIX.pattern!r}"
135 )
136
137 assert option.config_name is not None
138 config_dict[option.config_name] = final_value
139
140 return config_dict