summaryrefslogtreecommitdiff
path: root/src/flake8/options
diff options
context:
space:
mode:
authorCarl Meyer <carl@oddbird.net>2017-08-03 00:25:37 -0700
committerCarl Meyer <carl@oddbird.net>2017-08-03 00:25:37 -0700
commit4e58068657ece52e3f1636cb028e42c15b86fec3 (patch)
treec739fe9428a1a3f46d836773e243cdcdb22ddb27 /src/flake8/options
parent6df26ffd57178e50194aea31b3bf9c572f91fa54 (diff)
downloadflake8-4e58068657ece52e3f1636cb028e42c15b86fec3.tar.gz
Add support for local (in-repo, non-setuptools) plugins.
Closes #357
Diffstat (limited to 'src/flake8/options')
-rw-r--r--src/flake8/options/aggregator.py13
-rw-r--r--src/flake8/options/config.py99
2 files changed, 81 insertions, 31 deletions
diff --git a/src/flake8/options/aggregator.py b/src/flake8/options/aggregator.py
index 4075dc9..5b8ab9c 100644
--- a/src/flake8/options/aggregator.py
+++ b/src/flake8/options/aggregator.py
@@ -5,17 +5,18 @@ applies the user-specified command-line configuration on top of it.
"""
import logging
-from flake8 import utils
from flake8.options import config
LOG = logging.getLogger(__name__)
-def aggregate_options(manager, arglist=None, values=None):
+def aggregate_options(manager, config_finder, arglist=None, values=None):
"""Aggregate and merge CLI and config file options.
- :param flake8.option.manager.OptionManager manager:
+ :param flake8.options.manager.OptionManager manager:
The instance of the OptionManager that we're presently using.
+ :param flake8.options.config.ConfigFileFinder config_finder:
+ The config file finder to use.
:param list arglist:
The list of arguments to pass to ``manager.parse_args``. In most cases
this will be None so ``parse_args`` uses ``sys.argv``. This is mostly
@@ -32,14 +33,12 @@ def aggregate_options(manager, arglist=None, values=None):
default_values, _ = manager.parse_args([], values=values)
# Get original CLI values so we can find additional config file paths and
# see if --config was specified.
- original_values, original_args = manager.parse_args(arglist)
- extra_config_files = utils.normalize_paths(original_values.append_config)
+ original_values, _ = manager.parse_args(arglist)
# Make our new configuration file mergerator
config_parser = config.MergedConfigParser(
option_manager=manager,
- extra_config_files=extra_config_files,
- args=original_args,
+ config_finder=config_finder,
)
# Get the parsed config
diff --git a/src/flake8/options/config.py b/src/flake8/options/config.py
index a6ac63f..251697a 100644
--- a/src/flake8/options/config.py
+++ b/src/flake8/options/config.py
@@ -1,4 +1,5 @@
"""Config handling logic for Flake8."""
+import collections
import configparser
import logging
import os.path
@@ -49,6 +50,11 @@ class ConfigFileFinder(object):
args = ['.']
self.parent = self.tail = os.path.abspath(os.path.commonprefix(args))
+ # caches to avoid double-reading config files
+ self._local_configs = None
+ self._user_config = None
+ self._cli_configs = {}
+
@staticmethod
def _read_config(files):
config = configparser.RawConfigParser()
@@ -63,10 +69,12 @@ class ConfigFileFinder(object):
def cli_config(self, files):
"""Read and parse the config file specified on the command-line."""
- config, found_files = self._read_config(files)
- if found_files:
- LOG.debug('Found cli configuration files: %s', found_files)
- return config
+ if files not in self._cli_configs:
+ config, found_files = self._read_config(files)
+ if found_files:
+ LOG.debug('Found cli configuration files: %s', found_files)
+ self._cli_configs[files] = config
+ return self._cli_configs[files]
def generate_possible_local_files(self):
"""Find and generate all local config files."""
@@ -104,10 +112,12 @@ class ConfigFileFinder(object):
def local_configs(self):
"""Parse all local config files into one config object."""
- config, found_files = self._read_config(self.local_config_files())
- if found_files:
- LOG.debug('Found local configuration files: %s', found_files)
- return config
+ if self._local_configs is None:
+ config, found_files = self._read_config(self.local_config_files())
+ if found_files:
+ LOG.debug('Found local configuration files: %s', found_files)
+ self._local_configs = config
+ return self._local_configs
def user_config_file(self):
"""Find the user-level config file."""
@@ -117,10 +127,12 @@ class ConfigFileFinder(object):
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
+ if self._user_config is None:
+ config, found_files = self._read_config(self.user_config_file())
+ if found_files:
+ LOG.debug('Found user configuration files: %s', found_files)
+ self._user_config = config
+ return self._user_config
class MergedConfigParser(object):
@@ -138,30 +150,23 @@ class MergedConfigParser(object):
#: :meth:`~configparser.RawConfigParser.getbool` method.
GETBOOL_ACTIONS = {'store_true', 'store_false'}
- def __init__(self, option_manager, extra_config_files=None, args=None):
+ def __init__(self, option_manager, config_finder):
"""Initialize the MergedConfigParser instance.
- :param flake8.option.manager.OptionManager option_manager:
+ :param flake8.options.manager.OptionManager option_manager:
Initialized OptionManager.
- :param list extra_config_files:
- List of extra config files to parse.
- :params list args:
- The extra parsed arguments from the command-line.
+ :param flake8.options.config.ConfigFileFinder config_finder:
+ Initialized ConfigFileFinder.
"""
#: Our instance of flake8.options.manager.OptionManager
self.option_manager = option_manager
#: The prog value for the cli parser
self.program_name = option_manager.program_name
- #: Parsed extra arguments
- self.args = args
#: Mapping of configuration option names to
#: :class:`~flake8.options.manager.Option` instances
self.config_options = option_manager.config_options_dict
- #: List of extra config files
- self.extra_config_files = extra_config_files or []
#: Our instance of our :class:`~ConfigFileFinder`
- self.config_finder = ConfigFileFinder(self.program_name, self.args,
- self.extra_config_files)
+ self.config_finder = config_finder
def _normalize_value(self, option, value):
final_value = option.normalize(
@@ -280,3 +285,49 @@ class MergedConfigParser(object):
return self.parse_cli_config(cli_config)
return self.merge_user_and_local_config()
+
+
+def get_local_plugins(config_finder, cli_config=None, isolated=False):
+ """Get local plugins lists from config files.
+
+ :param flake8.options.config.ConfigFileFinder config_finder:
+ The config file finder to use.
+ :param str cli_config:
+ Value of --config when specified at the command-line. Overrides
+ all other config files.
+ :param bool isolated:
+ Determines if we should parse configuration files at all or not.
+ If running in isolated mode, we ignore all configuration files
+ :returns:
+ LocalPlugins namedtuple containing two lists of plugin strings,
+ one for extension (checker) plugins and one for report plugins.
+ :rtype:
+ flake8.options.config.LocalPlugins
+ """
+ local_plugins = LocalPlugins(extension=[], report=[])
+ if isolated:
+ LOG.debug('Refusing to look for local plugins in configuration'
+ 'files due to user-requested isolation')
+ return local_plugins
+
+ if cli_config:
+ LOG.debug('Reading local plugins only from "%s" specified via '
+ '--config by the user', cli_config)
+ configs = [config_finder.cli_config(cli_config)]
+ else:
+ configs = [
+ config_finder.user_config(),
+ config_finder.local_configs(),
+ ]
+
+ section = '%s:local-plugins' % config_finder.program_name
+ for config in configs:
+ for plugin_type in ['extension', 'report']:
+ if config.has_option(section, plugin_type):
+ getattr(local_plugins, plugin_type).extend(
+ config.get(section, plugin_type).strip().splitlines()
+ )
+ return local_plugins
+
+
+LocalPlugins = collections.namedtuple('LocalPlugins', 'extension report')