Skip to content

Commit 283f0c8

Browse files
authoredOct 11, 2021
Merge pull request #1404 from PyCQA/drop-xdg-config
Drop support for Home and XDG config files
2 parents 0b1c790 + 807904a commit 283f0c8

File tree

6 files changed

+49
-157
lines changed

6 files changed

+49
-157
lines changed
 

‎docs/source/internal/option_handling.rst

+11-20
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,8 @@ In |Flake8| 2, configuration file discovery and management was handled by
129129
pep8. In pep8's 1.6 release series, it drastically broke how discovery and
130130
merging worked (as a result of trying to improve it). To avoid a dependency
131131
breaking |Flake8| again in the future, we have created our own discovery and
132-
management.
133-
As part of managing this ourselves, we decided to change management/discovery
134-
for 3.0.0. We have done the following:
135-
136-
- User files (files stored in a user's home directory or in the XDG directory
137-
inside their home directory) are the first files read. For example, if the
138-
user has a ``~/.flake8`` file, we will read that first.
132+
management in 3.0.0. In 4.0.0 we have once again changed how this works and we
133+
removed support for user-level config files.
139134

140135
- Project files (files stored in the current directory) are read next and
141136
merged on top of the user file. In other words, configuration in project
@@ -157,7 +152,7 @@ To facilitate the configuration file management, we've taken a different
157152
approach to discovery and management of files than pep8. In pep8 1.5, 1.6, and
158153
1.7 configuration discovery and management was centralized in `66 lines of
159154
very terse python`_ which was confusing and not very explicit. The terseness
160-
of this function (|Flake8|'s authors believe) caused the confusion and
155+
of this function (|Flake8| 3.0.0's authors believe) caused the confusion and
161156
problems with pep8's 1.6 series. As such, |Flake8| has separated out
162157
discovery, management, and merging into a module to make reasoning about each
163158
of these pieces easier and more explicit (as well as easier to test).
@@ -176,23 +171,19 @@ to parse those configuration files.
176171
.. note:: ``local_config_files`` also filters out non-existent files.
177172

178173
Configuration file merging and managemnt is controlled by the
179-
:class:`~flake8.options.config.MergedConfigParser`. This requires the instance
174+
:class:`~flake8.options.config.ConfigParser`. This requires the instance
180175
of :class:`~flake8.options.manager.OptionManager` that the program is using,
181176
the list of appended config files, and the list of extra arguments. This
182177
object is currently the sole user of the
183178
:class:`~flake8.options.config.ConfigFileFinder` object. It appropriately
184179
initializes the object and uses it in each of
185180

186-
- :meth:`~flake8.options.config.MergedConfigParser.parse_cli_config`
187-
- :meth:`~flake8.options.config.MergedConfigParser.parse_local_config`
188-
- :meth:`~flake8.options.config.MergedConfigParser.parse_user_config`
181+
- :meth:`~flake8.options.config.ConfigParser.parse_cli_config`
182+
- :meth:`~flake8.options.config.ConfigParser.parse_local_config`
189183

190-
Finally,
191-
:meth:`~flake8.options.config.MergedConfigParser.merge_user_and_local_config`
192-
takes the user and local configuration files that are parsed by
193-
:meth:`~flake8.options.config.MergedConfigParser.parse_local_config` and
194-
:meth:`~flake8.options.config.MergedConfigParser.parse_user_config`. The
195-
main usage of the ``MergedConfigParser`` is in
184+
Finally, :meth:`~flake8.options.config.ConfigParser.parse` returns the
185+
appropriate configuration dictionary for this execution of |Flake8|. The
186+
main usage of the ``ConfigParser`` is in
196187
:func:`~flake8.options.aggregator.aggregate_options`.
197188

198189
Aggregating Configuration File and Command Line Arguments
@@ -201,7 +192,7 @@ Aggregating Configuration File and Command Line Arguments
201192
:func:`~flake8.options.aggregator.aggregate_options` accepts an instance of
202193
:class:`~flake8.options.manager.OptionManager` and does the work to parse the
203194
command-line arguments passed by the user necessary for creating an instance
204-
of :class:`~flake8.options.config.MergedConfigParser`.
195+
of :class:`~flake8.options.config.ConfigParser`.
205196

206197
After parsing the configuration file, we determine the default ignore list. We
207198
use the defaults from the OptionManager and update those with the parsed
@@ -229,6 +220,6 @@ API Documentation
229220
:members:
230221
:special-members:
231222

232-
.. autoclass:: flake8.options.config.MergedConfigParser
223+
.. autoclass:: flake8.options.config.ConfigParser
233224
:members:
234225
:special-members:

‎docs/source/release-notes/4.0.0.rst

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
4.0.0 -- 202x-mm-dd
2+
-------------------
3+
4+
You can view the `4.0.0 milestone`_ on GitHub for more details.
5+
6+
Backwards Incompatible Changes
7+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8+
9+
- Due to constant confusion by users, user-level |Flake8| configuration files
10+
are no longer supported. Files will not be searched for in the user's home
11+
directory (e.g., ``~/.flake8``) nor in the XDG config directory (e.g.,
12+
``~/.config/flake8``).
13+
14+
.. all links
15+
.. _4.0.0 milestone:
16+
https://github.com/PyCQA/flake8/milestone/39

‎docs/source/release-notes/index.rst

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
All of the release notes that have been recorded for Flake8 are organized here
66
with the newest releases first.
77

8+
4.x Release Series
9+
==================
10+
11+
.. toctree::
12+
4.0.0
13+
814
3.x Release Series
915
==================
1016

‎src/flake8/options/aggregator.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def aggregate_options(
3838
default_values, _ = manager.parse_args([])
3939

4040
# Make our new configuration file mergerator
41-
config_parser = config.MergedConfigParser(
41+
config_parser = config.ConfigParser(
4242
option_manager=manager, config_finder=config_finder
4343
)
4444

‎src/flake8/options/config.py

+5-59
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
LOG = logging.getLogger(__name__)
1313

14-
__all__ = ("ConfigFileFinder", "MergedConfigParser")
14+
__all__ = ("ConfigFileFinder", "ConfigParser")
1515

1616

1717
class ConfigFileFinder:
@@ -48,26 +48,12 @@ def __init__(
4848

4949
# User configuration file.
5050
self.program_name = program_name
51-
self.user_config_file = self._user_config_file(program_name)
5251

5352
# List of filenames to find in the local/project directory
5453
self.project_filenames = ("setup.cfg", "tox.ini", f".{program_name}")
5554

5655
self.local_directory = os.path.abspath(os.curdir)
5756

58-
@staticmethod
59-
def _user_config_file(program_name: str) -> str:
60-
if utils.is_windows():
61-
home_dir = os.path.expanduser("~")
62-
config_file_basename = f".{program_name}"
63-
else:
64-
home_dir = os.environ.get(
65-
"XDG_CONFIG_HOME", os.path.expanduser("~/.config")
66-
)
67-
config_file_basename = program_name
68-
69-
return os.path.join(home_dir, config_file_basename)
70-
7157
@staticmethod
7258
def _read_config(
7359
*files: str,
@@ -146,15 +132,8 @@ def local_configs(self):
146132
"""Parse all local config files into one config object."""
147133
return self.local_configs_with_files()[0]
148134

149-
def user_config(self):
150-
"""Parse the user config file into a config object."""
151-
config, found_files = self._read_config(self.user_config_file)
152-
if found_files:
153-
LOG.debug("Found user configuration files: %s", found_files)
154-
return config
155-
156135

157-
class MergedConfigParser:
136+
class ConfigParser:
158137
"""Encapsulate merging different types of configuration files.
159138
160139
This parses out the options registered that were specified in the
@@ -167,7 +146,7 @@ class MergedConfigParser:
167146
GETBOOL_ACTIONS = {"store_true", "store_false"}
168147

169148
def __init__(self, option_manager, config_finder):
170-
"""Initialize the MergedConfigParser instance.
149+
"""Initialize the ConfigParser instance.
171150
172151
:param flake8.options.manager.OptionManager option_manager:
173152
Initialized OptionManager.
@@ -239,19 +218,6 @@ def parse_local_config(self):
239218
LOG.debug("Parsing local configuration files.")
240219
return self._parse_config(config)
241220

242-
def parse_user_config(self):
243-
"""Parse and return the user configuration files."""
244-
config = self.config_finder.user_config()
245-
if not self.is_configured_by(config):
246-
LOG.debug(
247-
"User configuration files have no %s section",
248-
self.program_name,
249-
)
250-
return {}
251-
252-
LOG.debug("Parsing user configuration files.")
253-
return self._parse_config(config)
254-
255221
def parse_cli_config(self, config_path):
256222
"""Parse and return the file specified by --config."""
257223
config = self.config_finder.cli_config(config_path)
@@ -265,28 +231,8 @@ def parse_cli_config(self, config_path):
265231
LOG.debug("Parsing CLI configuration files.")
266232
return self._parse_config(config, os.path.dirname(config_path))
267233

268-
def merge_user_and_local_config(self):
269-
"""Merge the parsed user and local configuration files.
270-
271-
:returns:
272-
Dictionary of the parsed and merged configuration options.
273-
:rtype:
274-
dict
275-
"""
276-
user_config = self.parse_user_config()
277-
config = self.parse_local_config()
278-
279-
for option, value in user_config.items():
280-
config.setdefault(option, value)
281-
282-
return config
283-
284234
def parse(self):
285-
"""Parse and return the local and user config files.
286-
287-
First this copies over the parsed local configuration and then
288-
iterates over the options in the user configuration and sets them if
289-
they were not set by the local configuration file.
235+
"""Parse and return the local config files.
290236
291237
:returns:
292238
Dictionary of parsed configuration options
@@ -309,7 +255,7 @@ def parse(self):
309255
)
310256
return self.parse_cli_config(self.config_finder.config_file)
311257

312-
return self.merge_user_and_local_config()
258+
return self.parse_local_config()
313259

314260

315261
def get_local_plugins(config_finder):

‎tests/unit/test_merged_config_parser.py ‎tests/unit/test_config_parser.py

+10-77
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Unit tests for flake8.options.config.MergedConfigParser."""
1+
"""Unit tests for flake8.options.config.ConfigParser."""
22
import os
33
from unittest import mock
44

@@ -32,7 +32,7 @@ def test_parse_cli_config(optmanager, config_finder):
3232
"--ignore", parse_from_config=True, comma_separated_list=True
3333
)
3434
optmanager.add_option("--quiet", parse_from_config=True, action="count")
35-
parser = config.MergedConfigParser(optmanager, config_finder)
35+
parser = config.ConfigParser(optmanager, config_finder)
3636

3737
config_file = "tests/fixtures/config_files/cli-specified.ini"
3838
parsed_config = parser.parse_cli_config(config_file)
@@ -61,41 +61,11 @@ def test_is_configured_by(
6161
):
6262
"""Verify the behaviour of the is_configured_by method."""
6363
parsed_config, _ = config.ConfigFileFinder._read_config(filename)
64-
parser = config.MergedConfigParser(optmanager, config_finder)
64+
parser = config.ConfigParser(optmanager, config_finder)
6565

6666
assert parser.is_configured_by(parsed_config) is is_configured_by
6767

6868

69-
def test_parse_user_config(optmanager, config_finder):
70-
"""Verify parsing of user config files."""
71-
optmanager.add_option(
72-
"--exclude",
73-
parse_from_config=True,
74-
comma_separated_list=True,
75-
normalize_paths=True,
76-
)
77-
optmanager.add_option(
78-
"--ignore", parse_from_config=True, comma_separated_list=True
79-
)
80-
optmanager.add_option("--quiet", parse_from_config=True, action="count")
81-
parser = config.MergedConfigParser(optmanager, config_finder)
82-
83-
config_finder.user_config_file = (
84-
"tests/fixtures/config_files/" "cli-specified.ini"
85-
)
86-
parsed_config = parser.parse_user_config()
87-
88-
assert parsed_config == {
89-
"ignore": ["E123", "W234", "E111"],
90-
"exclude": [
91-
os.path.abspath("foo/"),
92-
os.path.abspath("bar/"),
93-
os.path.abspath("bogus/"),
94-
],
95-
"quiet": 1,
96-
}
97-
98-
9969
def test_parse_local_config(optmanager, config_finder):
10070
"""Verify parsing of local config files."""
10171
optmanager.add_option(
@@ -108,7 +78,7 @@ def test_parse_local_config(optmanager, config_finder):
10878
"--ignore", parse_from_config=True, comma_separated_list=True
10979
)
11080
optmanager.add_option("--quiet", parse_from_config=True, action="count")
111-
parser = config.MergedConfigParser(optmanager, config_finder)
81+
parser = config.ConfigParser(optmanager, config_finder)
11282

11383
with mock.patch.object(config_finder, "local_config_files") as localcfs:
11484
localcfs.return_value = [
@@ -127,47 +97,14 @@ def test_parse_local_config(optmanager, config_finder):
12797
}
12898

12999

130-
def test_merge_user_and_local_config(optmanager, config_finder):
131-
"""Verify merging of parsed user and local config files."""
132-
optmanager.add_option(
133-
"--exclude",
134-
parse_from_config=True,
135-
comma_separated_list=True,
136-
normalize_paths=True,
137-
)
138-
optmanager.add_option(
139-
"--ignore", parse_from_config=True, comma_separated_list=True
140-
)
141-
optmanager.add_option(
142-
"--select", parse_from_config=True, comma_separated_list=True
143-
)
144-
parser = config.MergedConfigParser(optmanager, config_finder)
145-
146-
with mock.patch.object(config_finder, "local_config_files") as localcfs:
147-
localcfs.return_value = [
148-
"tests/fixtures/config_files/local-config.ini"
149-
]
150-
config_finder.user_config_file = (
151-
"tests/fixtures/config_files/" "user-config.ini"
152-
)
153-
parsed_config = parser.merge_user_and_local_config()
154-
155-
assert parsed_config == {
156-
"exclude": [os.path.abspath("docs/")],
157-
"ignore": ["D203"],
158-
"select": ["E", "W", "F"],
159-
}
160-
161-
162100
def test_parse_isolates_config(optmanager):
163101
"""Verify behaviour of the parse method with isolated=True."""
164102
config_finder = mock.MagicMock()
165103
config_finder.ignore_config_files = True
166-
parser = config.MergedConfigParser(optmanager, config_finder)
104+
parser = config.ConfigParser(optmanager, config_finder)
167105

168106
assert parser.parse() == {}
169107
assert config_finder.local_configs.called is False
170-
assert config_finder.user_config.called is False
171108

172109

173110
def test_parse_uses_cli_config(optmanager):
@@ -176,7 +113,7 @@ def test_parse_uses_cli_config(optmanager):
176113
config_finder = mock.MagicMock()
177114
config_finder.config_file = config_file_value
178115
config_finder.ignore_config_files = False
179-
parser = config.MergedConfigParser(optmanager, config_finder)
116+
parser = config.ConfigParser(optmanager, config_finder)
180117

181118
parser.parse()
182119
config_finder.cli_config.assert_called_once_with(config_file_value)
@@ -206,13 +143,11 @@ def test_parsed_configs_are_equivalent(
206143
optmanager.add_option(
207144
"--ignore", parse_from_config=True, comma_separated_list=True
208145
)
209-
parser = config.MergedConfigParser(optmanager, config_finder)
146+
parser = config.ConfigParser(optmanager, config_finder)
210147

211148
with mock.patch.object(config_finder, "local_config_files") as localcfs:
212149
localcfs.return_value = [config_fixture_path]
213-
with mock.patch.object(config_finder, "user_config_file") as usercf:
214-
usercf.return_value = ""
215-
parsed_config = parser.merge_user_and_local_config()
150+
parsed_config = parser.parse()
216151

217152
assert parsed_config["ignore"] == ["E123", "W234", "E111"]
218153
assert parsed_config["exclude"] == [
@@ -243,13 +178,11 @@ def test_parsed_hyphenated_and_underscored_names(
243178
parse_from_config=True,
244179
comma_separated_list=True,
245180
)
246-
parser = config.MergedConfigParser(optmanager, config_finder)
181+
parser = config.ConfigParser(optmanager, config_finder)
247182

248183
with mock.patch.object(config_finder, "local_config_files") as localcfs:
249184
localcfs.return_value = [config_file]
250-
with mock.patch.object(config_finder, "user_config_file") as usercf:
251-
usercf.return_value = ""
252-
parsed_config = parser.merge_user_and_local_config()
185+
parsed_config = parser.parse()
253186

254187
assert parsed_config["max_line_length"] == 110
255188
assert parsed_config["enable_extensions"] == ["H101", "H235"]

0 commit comments

Comments
 (0)
Please sign in to comment.