mirror of
https://github.com/PyCQA/flake8.git
synced 2026-03-30 10:46:54 +00:00
Merge pull request #1404 from PyCQA/drop-xdg-config
Drop support for Home and XDG config files
This commit is contained in:
commit
283f0c8124
6 changed files with 49 additions and 157 deletions
|
|
@ -129,13 +129,8 @@ In |Flake8| 2, configuration file discovery and management was handled by
|
|||
pep8. In pep8's 1.6 release series, it drastically broke how discovery and
|
||||
merging worked (as a result of trying to improve it). To avoid a dependency
|
||||
breaking |Flake8| again in the future, we have created our own discovery and
|
||||
management.
|
||||
As part of managing this ourselves, we decided to change management/discovery
|
||||
for 3.0.0. We have done the following:
|
||||
|
||||
- User files (files stored in a user's home directory or in the XDG directory
|
||||
inside their home directory) are the first files read. For example, if the
|
||||
user has a ``~/.flake8`` file, we will read that first.
|
||||
management in 3.0.0. In 4.0.0 we have once again changed how this works and we
|
||||
removed support for user-level config files.
|
||||
|
||||
- Project files (files stored in the current directory) are read next and
|
||||
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
|
|||
approach to discovery and management of files than pep8. In pep8 1.5, 1.6, and
|
||||
1.7 configuration discovery and management was centralized in `66 lines of
|
||||
very terse python`_ which was confusing and not very explicit. The terseness
|
||||
of this function (|Flake8|'s authors believe) caused the confusion and
|
||||
of this function (|Flake8| 3.0.0's authors believe) caused the confusion and
|
||||
problems with pep8's 1.6 series. As such, |Flake8| has separated out
|
||||
discovery, management, and merging into a module to make reasoning about each
|
||||
of these pieces easier and more explicit (as well as easier to test).
|
||||
|
|
@ -176,23 +171,19 @@ to parse those configuration files.
|
|||
.. note:: ``local_config_files`` also filters out non-existent files.
|
||||
|
||||
Configuration file merging and managemnt is controlled by the
|
||||
:class:`~flake8.options.config.MergedConfigParser`. This requires the instance
|
||||
:class:`~flake8.options.config.ConfigParser`. This requires the instance
|
||||
of :class:`~flake8.options.manager.OptionManager` that the program is using,
|
||||
the list of appended config files, and the list of extra arguments. This
|
||||
object is currently the sole user of the
|
||||
:class:`~flake8.options.config.ConfigFileFinder` object. It appropriately
|
||||
initializes the object and uses it in each of
|
||||
|
||||
- :meth:`~flake8.options.config.MergedConfigParser.parse_cli_config`
|
||||
- :meth:`~flake8.options.config.MergedConfigParser.parse_local_config`
|
||||
- :meth:`~flake8.options.config.MergedConfigParser.parse_user_config`
|
||||
- :meth:`~flake8.options.config.ConfigParser.parse_cli_config`
|
||||
- :meth:`~flake8.options.config.ConfigParser.parse_local_config`
|
||||
|
||||
Finally,
|
||||
:meth:`~flake8.options.config.MergedConfigParser.merge_user_and_local_config`
|
||||
takes the user and local configuration files that are parsed by
|
||||
:meth:`~flake8.options.config.MergedConfigParser.parse_local_config` and
|
||||
:meth:`~flake8.options.config.MergedConfigParser.parse_user_config`. The
|
||||
main usage of the ``MergedConfigParser`` is in
|
||||
Finally, :meth:`~flake8.options.config.ConfigParser.parse` returns the
|
||||
appropriate configuration dictionary for this execution of |Flake8|. The
|
||||
main usage of the ``ConfigParser`` is in
|
||||
:func:`~flake8.options.aggregator.aggregate_options`.
|
||||
|
||||
Aggregating Configuration File and Command Line Arguments
|
||||
|
|
@ -201,7 +192,7 @@ Aggregating Configuration File and Command Line Arguments
|
|||
:func:`~flake8.options.aggregator.aggregate_options` accepts an instance of
|
||||
:class:`~flake8.options.manager.OptionManager` and does the work to parse the
|
||||
command-line arguments passed by the user necessary for creating an instance
|
||||
of :class:`~flake8.options.config.MergedConfigParser`.
|
||||
of :class:`~flake8.options.config.ConfigParser`.
|
||||
|
||||
After parsing the configuration file, we determine the default ignore list. We
|
||||
use the defaults from the OptionManager and update those with the parsed
|
||||
|
|
@ -229,6 +220,6 @@ API Documentation
|
|||
:members:
|
||||
:special-members:
|
||||
|
||||
.. autoclass:: flake8.options.config.MergedConfigParser
|
||||
.. autoclass:: flake8.options.config.ConfigParser
|
||||
:members:
|
||||
:special-members:
|
||||
|
|
|
|||
16
docs/source/release-notes/4.0.0.rst
Normal file
16
docs/source/release-notes/4.0.0.rst
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
4.0.0 -- 202x-mm-dd
|
||||
-------------------
|
||||
|
||||
You can view the `4.0.0 milestone`_ on GitHub for more details.
|
||||
|
||||
Backwards Incompatible Changes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Due to constant confusion by users, user-level |Flake8| configuration files
|
||||
are no longer supported. Files will not be searched for in the user's home
|
||||
directory (e.g., ``~/.flake8``) nor in the XDG config directory (e.g.,
|
||||
``~/.config/flake8``).
|
||||
|
||||
.. all links
|
||||
.. _4.0.0 milestone:
|
||||
https://github.com/PyCQA/flake8/milestone/39
|
||||
|
|
@ -5,6 +5,12 @@
|
|||
All of the release notes that have been recorded for Flake8 are organized here
|
||||
with the newest releases first.
|
||||
|
||||
4.x Release Series
|
||||
==================
|
||||
|
||||
.. toctree::
|
||||
4.0.0
|
||||
|
||||
3.x Release Series
|
||||
==================
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ def aggregate_options(
|
|||
default_values, _ = manager.parse_args([])
|
||||
|
||||
# Make our new configuration file mergerator
|
||||
config_parser = config.MergedConfigParser(
|
||||
config_parser = config.ConfigParser(
|
||||
option_manager=manager, config_finder=config_finder
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from flake8 import utils
|
|||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
__all__ = ("ConfigFileFinder", "MergedConfigParser")
|
||||
__all__ = ("ConfigFileFinder", "ConfigParser")
|
||||
|
||||
|
||||
class ConfigFileFinder:
|
||||
|
|
@ -48,26 +48,12 @@ class ConfigFileFinder:
|
|||
|
||||
# User configuration file.
|
||||
self.program_name = program_name
|
||||
self.user_config_file = self._user_config_file(program_name)
|
||||
|
||||
# List of filenames to find in the local/project directory
|
||||
self.project_filenames = ("setup.cfg", "tox.ini", f".{program_name}")
|
||||
|
||||
self.local_directory = os.path.abspath(os.curdir)
|
||||
|
||||
@staticmethod
|
||||
def _user_config_file(program_name: str) -> str:
|
||||
if utils.is_windows():
|
||||
home_dir = os.path.expanduser("~")
|
||||
config_file_basename = f".{program_name}"
|
||||
else:
|
||||
home_dir = os.environ.get(
|
||||
"XDG_CONFIG_HOME", os.path.expanduser("~/.config")
|
||||
)
|
||||
config_file_basename = program_name
|
||||
|
||||
return os.path.join(home_dir, config_file_basename)
|
||||
|
||||
@staticmethod
|
||||
def _read_config(
|
||||
*files: str,
|
||||
|
|
@ -146,15 +132,8 @@ class ConfigFileFinder:
|
|||
"""Parse all local config files into one config object."""
|
||||
return self.local_configs_with_files()[0]
|
||||
|
||||
def user_config(self):
|
||||
"""Parse the user config file into a config object."""
|
||||
config, found_files = self._read_config(self.user_config_file)
|
||||
if found_files:
|
||||
LOG.debug("Found user configuration files: %s", found_files)
|
||||
return config
|
||||
|
||||
|
||||
class MergedConfigParser:
|
||||
class ConfigParser:
|
||||
"""Encapsulate merging different types of configuration files.
|
||||
|
||||
This parses out the options registered that were specified in the
|
||||
|
|
@ -167,7 +146,7 @@ class MergedConfigParser:
|
|||
GETBOOL_ACTIONS = {"store_true", "store_false"}
|
||||
|
||||
def __init__(self, option_manager, config_finder):
|
||||
"""Initialize the MergedConfigParser instance.
|
||||
"""Initialize the ConfigParser instance.
|
||||
|
||||
:param flake8.options.manager.OptionManager option_manager:
|
||||
Initialized OptionManager.
|
||||
|
|
@ -239,19 +218,6 @@ class MergedConfigParser:
|
|||
LOG.debug("Parsing local configuration files.")
|
||||
return self._parse_config(config)
|
||||
|
||||
def parse_user_config(self):
|
||||
"""Parse and return the user configuration files."""
|
||||
config = self.config_finder.user_config()
|
||||
if not self.is_configured_by(config):
|
||||
LOG.debug(
|
||||
"User configuration files have no %s section",
|
||||
self.program_name,
|
||||
)
|
||||
return {}
|
||||
|
||||
LOG.debug("Parsing user configuration files.")
|
||||
return self._parse_config(config)
|
||||
|
||||
def parse_cli_config(self, config_path):
|
||||
"""Parse and return the file specified by --config."""
|
||||
config = self.config_finder.cli_config(config_path)
|
||||
|
|
@ -265,28 +231,8 @@ class MergedConfigParser:
|
|||
LOG.debug("Parsing CLI configuration files.")
|
||||
return self._parse_config(config, os.path.dirname(config_path))
|
||||
|
||||
def merge_user_and_local_config(self):
|
||||
"""Merge the parsed user and local configuration files.
|
||||
|
||||
:returns:
|
||||
Dictionary of the parsed and merged configuration options.
|
||||
:rtype:
|
||||
dict
|
||||
"""
|
||||
user_config = self.parse_user_config()
|
||||
config = self.parse_local_config()
|
||||
|
||||
for option, value in user_config.items():
|
||||
config.setdefault(option, value)
|
||||
|
||||
return config
|
||||
|
||||
def parse(self):
|
||||
"""Parse and return the local and user config files.
|
||||
|
||||
First this copies over the parsed local configuration and then
|
||||
iterates over the options in the user configuration and sets them if
|
||||
they were not set by the local configuration file.
|
||||
"""Parse and return the local config files.
|
||||
|
||||
:returns:
|
||||
Dictionary of parsed configuration options
|
||||
|
|
@ -309,7 +255,7 @@ class MergedConfigParser:
|
|||
)
|
||||
return self.parse_cli_config(self.config_finder.config_file)
|
||||
|
||||
return self.merge_user_and_local_config()
|
||||
return self.parse_local_config()
|
||||
|
||||
|
||||
def get_local_plugins(config_finder):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""Unit tests for flake8.options.config.MergedConfigParser."""
|
||||
"""Unit tests for flake8.options.config.ConfigParser."""
|
||||
import os
|
||||
from unittest import mock
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ def test_parse_cli_config(optmanager, config_finder):
|
|||
"--ignore", parse_from_config=True, comma_separated_list=True
|
||||
)
|
||||
optmanager.add_option("--quiet", parse_from_config=True, action="count")
|
||||
parser = config.MergedConfigParser(optmanager, config_finder)
|
||||
parser = config.ConfigParser(optmanager, config_finder)
|
||||
|
||||
config_file = "tests/fixtures/config_files/cli-specified.ini"
|
||||
parsed_config = parser.parse_cli_config(config_file)
|
||||
|
|
@ -61,41 +61,11 @@ def test_is_configured_by(
|
|||
):
|
||||
"""Verify the behaviour of the is_configured_by method."""
|
||||
parsed_config, _ = config.ConfigFileFinder._read_config(filename)
|
||||
parser = config.MergedConfigParser(optmanager, config_finder)
|
||||
parser = config.ConfigParser(optmanager, config_finder)
|
||||
|
||||
assert parser.is_configured_by(parsed_config) is is_configured_by
|
||||
|
||||
|
||||
def test_parse_user_config(optmanager, config_finder):
|
||||
"""Verify parsing of user config files."""
|
||||
optmanager.add_option(
|
||||
"--exclude",
|
||||
parse_from_config=True,
|
||||
comma_separated_list=True,
|
||||
normalize_paths=True,
|
||||
)
|
||||
optmanager.add_option(
|
||||
"--ignore", parse_from_config=True, comma_separated_list=True
|
||||
)
|
||||
optmanager.add_option("--quiet", parse_from_config=True, action="count")
|
||||
parser = config.MergedConfigParser(optmanager, config_finder)
|
||||
|
||||
config_finder.user_config_file = (
|
||||
"tests/fixtures/config_files/" "cli-specified.ini"
|
||||
)
|
||||
parsed_config = parser.parse_user_config()
|
||||
|
||||
assert parsed_config == {
|
||||
"ignore": ["E123", "W234", "E111"],
|
||||
"exclude": [
|
||||
os.path.abspath("foo/"),
|
||||
os.path.abspath("bar/"),
|
||||
os.path.abspath("bogus/"),
|
||||
],
|
||||
"quiet": 1,
|
||||
}
|
||||
|
||||
|
||||
def test_parse_local_config(optmanager, config_finder):
|
||||
"""Verify parsing of local config files."""
|
||||
optmanager.add_option(
|
||||
|
|
@ -108,7 +78,7 @@ def test_parse_local_config(optmanager, config_finder):
|
|||
"--ignore", parse_from_config=True, comma_separated_list=True
|
||||
)
|
||||
optmanager.add_option("--quiet", parse_from_config=True, action="count")
|
||||
parser = config.MergedConfigParser(optmanager, config_finder)
|
||||
parser = config.ConfigParser(optmanager, config_finder)
|
||||
|
||||
with mock.patch.object(config_finder, "local_config_files") as localcfs:
|
||||
localcfs.return_value = [
|
||||
|
|
@ -127,47 +97,14 @@ def test_parse_local_config(optmanager, config_finder):
|
|||
}
|
||||
|
||||
|
||||
def test_merge_user_and_local_config(optmanager, config_finder):
|
||||
"""Verify merging of parsed user and local config files."""
|
||||
optmanager.add_option(
|
||||
"--exclude",
|
||||
parse_from_config=True,
|
||||
comma_separated_list=True,
|
||||
normalize_paths=True,
|
||||
)
|
||||
optmanager.add_option(
|
||||
"--ignore", parse_from_config=True, comma_separated_list=True
|
||||
)
|
||||
optmanager.add_option(
|
||||
"--select", parse_from_config=True, comma_separated_list=True
|
||||
)
|
||||
parser = config.MergedConfigParser(optmanager, config_finder)
|
||||
|
||||
with mock.patch.object(config_finder, "local_config_files") as localcfs:
|
||||
localcfs.return_value = [
|
||||
"tests/fixtures/config_files/local-config.ini"
|
||||
]
|
||||
config_finder.user_config_file = (
|
||||
"tests/fixtures/config_files/" "user-config.ini"
|
||||
)
|
||||
parsed_config = parser.merge_user_and_local_config()
|
||||
|
||||
assert parsed_config == {
|
||||
"exclude": [os.path.abspath("docs/")],
|
||||
"ignore": ["D203"],
|
||||
"select": ["E", "W", "F"],
|
||||
}
|
||||
|
||||
|
||||
def test_parse_isolates_config(optmanager):
|
||||
"""Verify behaviour of the parse method with isolated=True."""
|
||||
config_finder = mock.MagicMock()
|
||||
config_finder.ignore_config_files = True
|
||||
parser = config.MergedConfigParser(optmanager, config_finder)
|
||||
parser = config.ConfigParser(optmanager, config_finder)
|
||||
|
||||
assert parser.parse() == {}
|
||||
assert config_finder.local_configs.called is False
|
||||
assert config_finder.user_config.called is False
|
||||
|
||||
|
||||
def test_parse_uses_cli_config(optmanager):
|
||||
|
|
@ -176,7 +113,7 @@ def test_parse_uses_cli_config(optmanager):
|
|||
config_finder = mock.MagicMock()
|
||||
config_finder.config_file = config_file_value
|
||||
config_finder.ignore_config_files = False
|
||||
parser = config.MergedConfigParser(optmanager, config_finder)
|
||||
parser = config.ConfigParser(optmanager, config_finder)
|
||||
|
||||
parser.parse()
|
||||
config_finder.cli_config.assert_called_once_with(config_file_value)
|
||||
|
|
@ -206,13 +143,11 @@ def test_parsed_configs_are_equivalent(
|
|||
optmanager.add_option(
|
||||
"--ignore", parse_from_config=True, comma_separated_list=True
|
||||
)
|
||||
parser = config.MergedConfigParser(optmanager, config_finder)
|
||||
parser = config.ConfigParser(optmanager, config_finder)
|
||||
|
||||
with mock.patch.object(config_finder, "local_config_files") as localcfs:
|
||||
localcfs.return_value = [config_fixture_path]
|
||||
with mock.patch.object(config_finder, "user_config_file") as usercf:
|
||||
usercf.return_value = ""
|
||||
parsed_config = parser.merge_user_and_local_config()
|
||||
parsed_config = parser.parse()
|
||||
|
||||
assert parsed_config["ignore"] == ["E123", "W234", "E111"]
|
||||
assert parsed_config["exclude"] == [
|
||||
|
|
@ -243,13 +178,11 @@ def test_parsed_hyphenated_and_underscored_names(
|
|||
parse_from_config=True,
|
||||
comma_separated_list=True,
|
||||
)
|
||||
parser = config.MergedConfigParser(optmanager, config_finder)
|
||||
parser = config.ConfigParser(optmanager, config_finder)
|
||||
|
||||
with mock.patch.object(config_finder, "local_config_files") as localcfs:
|
||||
localcfs.return_value = [config_file]
|
||||
with mock.patch.object(config_finder, "user_config_file") as usercf:
|
||||
usercf.return_value = ""
|
||||
parsed_config = parser.merge_user_and_local_config()
|
||||
parsed_config = parser.parse()
|
||||
|
||||
assert parsed_config["max_line_length"] == 110
|
||||
assert parsed_config["enable_extensions"] == ["H101", "H235"]
|
||||
Loading…
Add table
Add a link
Reference in a new issue