[Python-modules-commits] [python-flake8] 01/08: Import python-flake8_3.5.0.orig.tar.gz
Ondrej Novy
onovy at debian.org
Sat Dec 9 23:33:58 UTC 2017
This is an automated email from the git hooks/post-receive script.
onovy pushed a commit to branch master
in repository python-flake8.
commit 61375eeebdf6b009c9c469323bd4069c9d746270
Author: Ondřej Nový <onovy at debian.org>
Date: Sun Dec 10 00:11:28 2017 +0100
Import python-flake8_3.5.0.orig.tar.gz
---
PKG-INFO | 3 +-
docs/source/release-notes/3.5.0.rst | 46 ++++++++++
docs/source/release-notes/index.rst | 1 +
docs/source/user/configuration.rst | 48 +++++++++++
setup.cfg | 2 +-
setup.py | 10 ++-
src/flake8.egg-info/PKG-INFO | 3 +-
src/flake8.egg-info/SOURCES.txt | 4 +
src/flake8.egg-info/entry_points.txt | 2 +
src/flake8.egg-info/requires.txt | 8 +-
src/flake8/__init__.py | 2 +-
src/flake8/api/legacy.py | 5 ++
src/flake8/checker.py | 2 +
src/flake8/defaults.py | 2 +-
src/flake8/main/application.py | 112 +++++++++++++++++-------
src/flake8/main/debug.py | 10 ++-
src/flake8/main/git.py | 6 ++
src/flake8/main/mercurial.py | 20 ++++-
src/flake8/options/aggregator.py | 13 ++-
src/flake8/options/config.py | 122 ++++++++++++++++++++-------
src/flake8/options/manager.py | 17 ++--
src/flake8/plugins/manager.py | 60 ++++++++++---
src/flake8/utils.py | 10 ++-
tests/fixtures/config_files/README.rst | 10 ++-
tests/fixtures/config_files/local-plugin.ini | 5 ++
tests/integration/test_aggregator.py | 9 +-
tests/integration/test_plugins.py | 58 +++++++++++++
tests/unit/test_application.py | 59 +++++++------
tests/unit/test_config_file_finder.py | 37 +++++++-
tests/unit/test_debug.py | 35 +++++---
tests/unit/test_get_local_plugins.py | 41 +++++++++
tests/unit/test_legacy_api.py | 4 +
tests/unit/test_merged_config_parser.py | 81 +++++++-----------
tests/unit/test_option_manager.py | 38 +++++----
tests/unit/test_plugin_manager.py | 12 +++
tests/unit/test_plugin_type_manager.py | 2 +-
tests/unit/test_utils.py | 1 +
tests/unit/test_violation.py | 1 +
38 files changed, 682 insertions(+), 219 deletions(-)
diff --git a/PKG-INFO b/PKG-INFO
index c689934..e118cf0 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,11 +1,12 @@
Metadata-Version: 1.1
Name: flake8
-Version: 3.4.1
+Version: 3.5.0
Summary: the modular source code checker: pep8, pyflakes and co
Home-page: https://gitlab.com/pycqa/flake8
Author: Ian Stapleton Cordasco
Author-email: graffatcolmingov at gmail.com
License: MIT
+Description-Content-Type: UNKNOWN
Description: ========
Flake8
========
diff --git a/docs/source/release-notes/3.5.0.rst b/docs/source/release-notes/3.5.0.rst
new file mode 100644
index 0000000..ff3a140
--- /dev/null
+++ b/docs/source/release-notes/3.5.0.rst
@@ -0,0 +1,46 @@
+3.5.0 -- 2017-10-23
+-------------------
+
+You can view the `3.5.0 milestone`_ on GitLab for more details.
+
+New Dependency Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Allow for PyFlakes 1.6.0 (See also `GitLab#359`_)
+
+- Start using new PyCodestyle checks for bare excepts and ambiguous identifier
+ (See also `GitLab#361`_)
+
+Features
+~~~~~~~~
+
+- Print out information about configuring VCS hooks (See also `GitLab#335`_)
+
+- Allow users to develop plugins "local" to a repository without using
+ setuptools. See our documentation on local plugins for more information.
+ (See also `GitLab#357`_)
+
+Bugs Fixed
+~~~~~~~~~~
+
+- Catch and helpfully report ``UnicodeDecodeError``\ s when parsing
+ configuration files. (See also `GitLab#358`_)
+
+
+.. all links
+.. _3.5.0 milestone:
+ https://gitlab.com/pycqa/flake8/milestones/20
+
+.. issue links
+.. _GitLab#335:
+ https://gitlab.com/pycqa/flake8/issues/335
+.. _GitLab#357:
+ https://gitlab.com/pycqa/flake8/issues/357
+.. _GitLab#358:
+ https://gitlab.com/pycqa/flake8/issues/358
+.. _GitLab#359:
+ https://gitlab.com/pycqa/flake8/issues/359
+.. _GitLab#361:
+ https://gitlab.com/pycqa/flake8/issues/361
+
+.. merge request links
diff --git a/docs/source/release-notes/index.rst b/docs/source/release-notes/index.rst
index b15d937..99f5dcf 100644
--- a/docs/source/release-notes/index.rst
+++ b/docs/source/release-notes/index.rst
@@ -9,6 +9,7 @@ with the newest releases first.
==================
.. toctree::
+ 3.5.0
3.4.1
3.4.0
3.3.0
diff --git a/docs/source/user/configuration.rst b/docs/source/user/configuration.rst
index 5e81807..eacacef 100644
--- a/docs/source/user/configuration.rst
+++ b/docs/source/user/configuration.rst
@@ -222,3 +222,51 @@ They use the comments to describe the check but they could also write this as:
Or they could use each comment to describe **why** they've ignored the check.
|Flake8| knows how to parse these lists and will appropriately handle
these situations.
+
+
+Using Local Plugins
+-------------------
+
+.. versionadded:: 3.5.0
+
+|Flake8| allows users to write plugins that live locally in a project. These
+plugins do not need to use setuptools or any of the other overhead associated
+with plugins distributed on PyPI. To use these plugins, users must specify
+them in their configuration file (i.e., ``.flake8``, ``setup.cfg``, or
+``tox.ini``). This must be configured in a separate INI section named
+``flake8:local-plugins``.
+
+Users may configure plugins that check source code, i.e., ``extension``
+plugins, and plugins that report errors, i.e., ``report`` plugins.
+
+An example configuration might look like:
+
+.. code-block:: ini
+
+ [flake8:local-plugins]
+ extension =
+ MC1 = project.flake8.checkers:MyChecker1
+ MC2 = project.flake8.checkers:MyChecker2
+ report =
+ MR1 = project.flake8.reporters:MyReporter1
+ MR2 = project.flake8.reporters:MyReporter2
+
+|Flake8| will also, however, allow for commas to separate the plugins for
+example:
+
+.. code-block:: ini
+
+ [flake8:local-plugins]
+ extension =
+ MC1 = project.flake8.checkers:MyChecker1,
+ MC2 = project.flake8.checkers:MyChecker2
+ report =
+ MR1 = project.flake8.reporters:MyReporter1,
+ MR2 = project.flake8.reporters:MyReporter2
+
+These configurations will allow you to select your own custom reporter plugin
+that you've designed or will utilize your new check classes.
+
+.. note::
+
+ These plugins otherwise follow the same guidelines as regular plugins.
diff --git a/setup.cfg b/setup.cfg
index de6418f..d1c2524 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -8,7 +8,7 @@ universal = 1
requires-dist =
enum34; python_version<"3.4"
configparser; python_version<"3.2"
- pyflakes >= 1.5.0, < 1.6.0
+ pyflakes >= 1.5.0, < 1.7.0
pycodestyle >= 2.0.0, < 2.4.0
mccabe >= 0.6.0, < 0.7.0
diff --git a/setup.py b/setup.py
index de350a8..aa45e43 100644
--- a/setup.py
+++ b/setup.py
@@ -17,7 +17,11 @@ tests_require = ['mock >= 2.0.0', 'pytest']
# NOTE(sigmavirus24): When updating these requirements, update them in
# setup.cfg as well.
requires = [
- "pyflakes >= 1.5.0, < 1.6.0",
+ # We document the reasoning for using ranges here:
+ # http://flake8.pycqa.org/en/latest/faq.html#why-does-flake8-use-ranges-for-its-dependencies
+ # And in which releases we will update those ranges here:
+ # http://flake8.pycqa.org/en/latest/internal/releases.html#releasing-flake8
+ "pyflakes >= 1.5.0, < 1.7.0",
"pycodestyle >= 2.0.0, < 2.4.0",
"mccabe >= 0.6.0, < 0.7.0",
"setuptools >= 30",
@@ -108,8 +112,8 @@ setuptools.setup(
PEP8_PLUGIN('comparison_to_singleton'),
PEP8_PLUGIN('comparison_negative'),
PEP8_PLUGIN('comparison_type'),
- # NOTE(sigmavirus24): Add this back once PyCodestyle 2.1.0 is out
- # PEP8_PLUGIN('ambiguous_identifier'),
+ PEP8_PLUGIN('ambiguous_identifier'),
+ PEP8_PLUGIN('bare_except'),
PEP8_PLUGIN('python_3000_has_key'),
PEP8_PLUGIN('python_3000_raise_comma'),
PEP8_PLUGIN('python_3000_not_equal'),
diff --git a/src/flake8.egg-info/PKG-INFO b/src/flake8.egg-info/PKG-INFO
index c689934..e118cf0 100644
--- a/src/flake8.egg-info/PKG-INFO
+++ b/src/flake8.egg-info/PKG-INFO
@@ -1,11 +1,12 @@
Metadata-Version: 1.1
Name: flake8
-Version: 3.4.1
+Version: 3.5.0
Summary: the modular source code checker: pep8, pyflakes and co
Home-page: https://gitlab.com/pycqa/flake8
Author: Ian Stapleton Cordasco
Author-email: graffatcolmingov at gmail.com
License: MIT
+Description-Content-Type: UNKNOWN
Description: ========
Flake8
========
diff --git a/src/flake8.egg-info/SOURCES.txt b/src/flake8.egg-info/SOURCES.txt
index 159c19f..440bcef 100644
--- a/src/flake8.egg-info/SOURCES.txt
+++ b/src/flake8.egg-info/SOURCES.txt
@@ -76,6 +76,7 @@ docs/source/release-notes/3.2.1.rst
docs/source/release-notes/3.3.0.rst
docs/source/release-notes/3.4.0.rst
docs/source/release-notes/3.4.1.rst
+docs/source/release-notes/3.5.0.rst
docs/source/release-notes/index.rst
docs/source/user/configuration.rst
docs/source/user/error-codes.rst
@@ -132,6 +133,7 @@ tests/fixtures/config_files/cli-specified-without-inline-comments.ini
tests/fixtures/config_files/cli-specified.ini
tests/fixtures/config_files/config-with-hyphenated-options.ini
tests/fixtures/config_files/local-config.ini
+tests/fixtures/config_files/local-plugin.ini
tests/fixtures/config_files/no-flake8-section.ini
tests/fixtures/config_files/user-config.ini
tests/fixtures/diffs/multi_file_diff
@@ -143,6 +145,7 @@ tests/fixtures/example-code/inline-ignores/E501.py
tests/fixtures/example-code/inline-ignores/E731.py
tests/integration/test_aggregator.py
tests/integration/test_checker.py
+tests/integration/test_plugins.py
tests/unit/test_application.py
tests/unit/test_base_formatter.py
tests/unit/test_checker_manager.py
@@ -152,6 +155,7 @@ tests/unit/test_decision_engine.py
tests/unit/test_file_checker.py
tests/unit/test_file_processor.py
tests/unit/test_filenameonly_formatter.py
+tests/unit/test_get_local_plugins.py
tests/unit/test_git.py
tests/unit/test_legacy_api.py
tests/unit/test_merged_config_parser.py
diff --git a/src/flake8.egg-info/entry_points.txt b/src/flake8.egg-info/entry_points.txt
index 2b6ef95..5c15ca6 100644
--- a/src/flake8.egg-info/entry_points.txt
+++ b/src/flake8.egg-info/entry_points.txt
@@ -6,6 +6,8 @@ flake8 = flake8.main.setuptools_command:Flake8
[flake8.extension]
F = flake8.plugins.pyflakes:FlakesChecker
+pycodestyle.ambiguous_identifier = pycodestyle:ambiguous_identifier
+pycodestyle.bare_except = pycodestyle:bare_except
pycodestyle.blank_lines = pycodestyle:blank_lines
pycodestyle.break_around_binary_operator = pycodestyle:break_around_binary_operator
pycodestyle.comparison_negative = pycodestyle:comparison_negative
diff --git a/src/flake8.egg-info/requires.txt b/src/flake8.egg-info/requires.txt
index c9e0506..66c3062 100644
--- a/src/flake8.egg-info/requires.txt
+++ b/src/flake8.egg-info/requires.txt
@@ -1,7 +1,7 @@
-pyflakes >= 1.5.0, < 1.6.0
-pycodestyle >= 2.0.0, < 2.4.0
-mccabe >= 0.6.0, < 0.7.0
-setuptools >= 30
+pyflakes<1.7.0,>=1.5.0
+pycodestyle<2.4.0,>=2.0.0
+mccabe<0.7.0,>=0.6.0
+setuptools>=30
[:python_version<'3.2']
configparser
diff --git a/src/flake8/__init__.py b/src/flake8/__init__.py
index 80fe44e..efb711c 100644
--- a/src/flake8/__init__.py
+++ b/src/flake8/__init__.py
@@ -27,7 +27,7 @@ LOG.addHandler(NullHandler())
# Clean up after LOG config
del NullHandler
-__version__ = '3.4.1'
+__version__ = '3.5.0'
__version_info__ = tuple(int(i) for i in __version__.split('.') if i.isdigit())
diff --git a/src/flake8/api/legacy.py b/src/flake8/api/legacy.py
index 2b983c8..b332860 100644
--- a/src/flake8/api/legacy.py
+++ b/src/flake8/api/legacy.py
@@ -6,6 +6,7 @@ In 3.0 we no longer have an "engine" module but we maintain the API from it.
import logging
import os.path
+import flake8
from flake8.formatting import base as formatter
from flake8.main import application as app
@@ -26,6 +27,10 @@ def get_style_guide(**kwargs):
:class:`StyleGuide`
"""
application = app.Application()
+ application.parse_preliminary_options_and_args([])
+ flake8.configure_logging(
+ application.prelim_opts.verbose, application.prelim_opts.output_file)
+ application.make_config_finder()
application.find_plugins()
application.register_plugin_options()
application.parse_configuration_and_cli([])
diff --git a/src/flake8/checker.py b/src/flake8/checker.py
index 569eafa..6e53cb5 100644
--- a/src/flake8/checker.py
+++ b/src/flake8/checker.py
@@ -209,6 +209,7 @@ class Manager(object):
filename_patterns = self.options.filename
running_from_vcs = self.options._running_from_vcs
+ running_from_diff = self.options.diff
# NOTE(sigmavirus24): Yes this is a little unsightly, but it's our
# best solution right now.
@@ -227,6 +228,7 @@ class Manager(object):
# If it was specified explicitly, the user intended for it to be
# checked.
explicitly_provided = (not running_from_vcs and
+ not running_from_diff and
(argument == filename))
return ((file_exists and
(explicitly_provided or matches_filename_patterns)) or
diff --git a/src/flake8/defaults.py b/src/flake8/defaults.py
index e8c6bfb..55cb48a 100644
--- a/src/flake8/defaults.py
+++ b/src/flake8/defaults.py
@@ -46,7 +46,7 @@ NOQA_INLINE_REGEXP = re.compile(
# We do not care about the ``: `` that follows ``noqa``
# We do not care about the casing of ``noqa``
# We want a comma-separated list of errors
- '# noqa(?:: (?P<codes>([A-Z][0-9]+,?)+))?',
+ '# noqa(?:: (?P<codes>([A-Z][0-9]+(?:[,\s]+)?)+))?',
re.IGNORECASE
)
diff --git a/src/flake8/main/application.py b/src/flake8/main/application.py
index 293ac92..6c68305 100644
--- a/src/flake8/main/application.py
+++ b/src/flake8/main/application.py
@@ -12,7 +12,7 @@ from flake8 import exceptions
from flake8 import style_guide
from flake8 import utils
from flake8.main import options
-from flake8.options import aggregator
+from flake8.options import aggregator, config
from flake8.options import manager
from flake8.plugins import manager as plugin_manager
@@ -45,34 +45,16 @@ class Application(object):
prog='flake8', version=flake8.__version__
)
options.register_default_options(self.option_manager)
-
- # We haven't found or registered our plugins yet, so let's defer
- # printing the version until we aggregate options from config files
- # and the command-line. First, let's clone our arguments on the CLI,
- # then we'll attempt to remove ``--version`` so that we can avoid
- # triggering the "version" action in optparse. If it's not there, we
- # do not need to worry and we can continue. If it is, we successfully
- # defer printing the version until just a little bit later.
- # Similarly we have to defer printing the help text until later.
- args = sys.argv[:]
- try:
- args.remove('--version')
- except ValueError:
- pass
- try:
- args.remove('--help')
- except ValueError:
- pass
- try:
- args.remove('-h')
- except ValueError:
- pass
-
- preliminary_opts, _ = self.option_manager.parse_known_args(args)
- # Set the verbosity of the program
- flake8.configure_logging(preliminary_opts.verbose,
- preliminary_opts.output_file)
-
+ #: The preliminary options parsed from CLI before plugins are loaded,
+ #: into a :class:`optparse.Values` instance
+ self.prelim_opts = None
+ #: The preliminary arguments parsed from CLI before plugins are loaded
+ self.prelim_args = None
+ #: The instance of :class:`flake8.options.config.ConfigFileFinder`
+ self.config_finder = None
+
+ #: The :class:`flake8.options.config.LocalPlugins` found in config
+ self.local_plugins = None
#: The instance of :class:`flake8.plugins.manager.Checkers`
self.check_plugins = None
#: The instance of :class:`flake8.plugins.manager.Listeners`
@@ -111,6 +93,48 @@ class Application(object):
#: The parsed diff information
self.parsed_diff = {}
+ def parse_preliminary_options_and_args(self, argv=None):
+ """Get preliminary options and args from CLI, pre-plugin-loading.
+
+ We need to know the values of a few standard options and args now, so
+ that we can find config files and configure logging.
+
+ Since plugins aren't loaded yet, there may be some as-yet-unknown
+ options; we ignore those for now, they'll be parsed later when we do
+ real option parsing.
+
+ Sets self.prelim_opts and self.prelim_args.
+
+ :param list argv:
+ Command-line arguments passed in directly.
+ """
+ # We haven't found or registered our plugins yet, so let's defer
+ # printing the version until we aggregate options from config files
+ # and the command-line. First, let's clone our arguments on the CLI,
+ # then we'll attempt to remove ``--version`` so that we can avoid
+ # triggering the "version" action in optparse. If it's not there, we
+ # do not need to worry and we can continue. If it is, we successfully
+ # defer printing the version until just a little bit later.
+ # Similarly we have to defer printing the help text until later.
+ args = (argv or sys.argv)[:]
+ try:
+ args.remove('--version')
+ except ValueError:
+ pass
+ try:
+ args.remove('--help')
+ except ValueError:
+ pass
+ try:
+ args.remove('-h')
+ except ValueError:
+ pass
+
+ opts, args = self.option_manager.parse_known_args(args)
+ # parse_known_args includes program name and unknown options as args
+ args = [a for a in args[1:] if not a.startswith('-')]
+ self.prelim_opts, self.prelim_args = opts, args
+
def exit(self):
# type: () -> NoneType
"""Handle finalization and exiting the program.
@@ -125,6 +149,17 @@ class Application(object):
raise SystemExit((self.result_count > 0) or
self.catastrophic_failure)
+ def make_config_finder(self):
+ """Make our ConfigFileFinder based on preliminary opts and args."""
+ if self.config_finder is None:
+ extra_config_files = utils.normalize_paths(
+ self.prelim_opts.append_config)
+ self.config_finder = config.ConfigFileFinder(
+ self.option_manager.program_name,
+ self.prelim_args,
+ extra_config_files,
+ )
+
def find_plugins(self):
# type: () -> NoneType
"""Find and load the plugins for this application.
@@ -135,14 +170,23 @@ class Application(object):
of finding plugins (via :mod:`pkg_resources`) we want this to be
idempotent and so only update those attributes if they are ``None``.
"""
+ if self.local_plugins is None:
+ self.local_plugins = config.get_local_plugins(
+ self.config_finder,
+ self.prelim_opts.config,
+ self.prelim_opts.isolated,
+ )
+
if self.check_plugins is None:
- self.check_plugins = plugin_manager.Checkers()
+ self.check_plugins = plugin_manager.Checkers(
+ self.local_plugins.extension)
if self.listening_plugins is None:
self.listening_plugins = plugin_manager.Listeners()
if self.formatting_plugins is None:
- self.formatting_plugins = plugin_manager.ReportFormatters()
+ self.formatting_plugins = plugin_manager.ReportFormatters(
+ self.local_plugins.report)
self.check_plugins.load_plugins()
self.listening_plugins.load_plugins()
@@ -165,7 +209,7 @@ class Application(object):
"""
if self.options is None and self.args is None:
self.options, self.args = aggregator.aggregate_options(
- self.option_manager, argv
+ self.option_manager, self.config_finder, argv
)
self.running_against_diff = self.options.diff
@@ -314,6 +358,10 @@ class Application(object):
"""
# NOTE(sigmavirus24): When updating this, make sure you also update
# our legacy API calls to these same methods.
+ self.parse_preliminary_options_and_args(argv)
+ flake8.configure_logging(
+ self.prelim_opts.verbose, self.prelim_opts.output_file)
+ self.make_config_finder()
self.find_plugins()
self.register_plugin_options()
self.parse_configuration_and_cli(argv)
diff --git a/src/flake8/main/debug.py b/src/flake8/main/debug.py
index e6ea141..ca3827e 100644
--- a/src/flake8/main/debug.py
+++ b/src/flake8/main/debug.py
@@ -53,8 +53,14 @@ def information(option_manager):
def plugins_from(option_manager):
"""Generate the list of plugins installed."""
- return [{'plugin': plugin, 'version': version}
- for (plugin, version) in sorted(option_manager.registered_plugins)]
+ return [
+ {
+ 'plugin': plugin.name,
+ 'version': plugin.version,
+ 'is_local': plugin.local,
+ }
+ for plugin in sorted(option_manager.registered_plugins)
+ ]
def dependencies():
diff --git a/src/flake8/main/git.py b/src/flake8/main/git.py
index 3cda3c5..ad55100 100644
--- a/src/flake8/main/git.py
+++ b/src/flake8/main/git.py
@@ -68,6 +68,8 @@ def install():
pre-commit python script in the hooks sub-directory if one does not
already exist.
+ It will also print a message to stdout about how to configure the hook.
+
:returns:
True if successful, False if the git directory doesn't exist.
:rtype:
@@ -105,6 +107,10 @@ def install():
# so that git can actually execute it as a hook.
pre_commit_permissions = stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH
os.chmod(pre_commit_file, pre_commit_permissions)
+
+ print('git pre-commit hook installed, for configuration options see')
+ print('http://flake8.pycqa.org/en/latest/user/using-hooks.html')
+
return True
diff --git a/src/flake8/main/mercurial.py b/src/flake8/main/mercurial.py
index a46f676..344c9f7 100644
--- a/src/flake8/main/mercurial.py
+++ b/src/flake8/main/mercurial.py
@@ -46,7 +46,22 @@ def hook(ui, repo, **kwargs):
def install():
- """Ensure that the mercurial hooks are installed."""
+ """Ensure that the mercurial hooks are installed.
+
+ This searches for the ``.hg/hgrc`` configuration file and will add commit
+ and qrefresh hooks to it, if they do not already exist.
+
+ It will also print a message to stdout about how to configure the hook.
+
+ :returns:
+ True if successful, False if the ``.hg/hgrc`` file doesn't exist.
+ :rtype:
+ bool
+ :raises:
+ flake8.exceptions.MercurialCommitHookAlreadyExists
+ :raises:
+ flake8.exceptions.MercurialQRefreshHookAlreadyExists
+ """
hgrc = find_hgrc(create_if_missing=True)
if hgrc is None:
return False
@@ -80,6 +95,9 @@ def install():
with open(hgrc, 'w') as fd:
hgconfig.write(fd)
+ print('mercurial hooks installed, for configuration options see')
+ print('http://flake8.pycqa.org/en/latest/user/using-hooks.html')
+
return True
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..71429af 100644
--- a/src/flake8/options/config.py
+++ b/src/flake8/options/config.py
@@ -1,9 +1,12 @@
"""Config handling logic for Flake8."""
+import collections
import configparser
import logging
import os.path
import sys
+from flake8 import utils
+
LOG = logging.getLogger(__name__)
__all__ = ('ConfigFileFinder', 'MergedConfigParser')
@@ -49,24 +52,39 @@ 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()
- try:
- found_files = config.read(files)
- except configparser.ParsingError:
- LOG.exception("There was an error trying to parse a config "
- "file. The files we were attempting to parse "
- "were: %r", files)
- found_files = []
+ if isinstance(files, (str, type(u''))):
+ files = [files]
+
+ found_files = []
+ for filename in files:
+ try:
+ found_files.extend(config.read(filename))
+ except UnicodeDecodeError:
+ LOG.exception("There was an error decoding a config file."
+ "The file with a problem was %s.",
+ filename)
+ except configparser.ParsingError:
+ LOG.exception("There was an error trying to parse a config "
+ "file. The file with a problem was %s.",
+ filename)
return (config, found_files)
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 +122,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 +137,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 +160,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 +295,48 @@ 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)
+ config = config_finder.cli_config(cli_config)
+ else:
+ config = config_finder.local_configs()
+
+ section = '%s:local-plugins' % config_finder.program_name
+ for plugin_type in ['extension', 'report']:
+ if config.has_option(section, plugin_type):
+ local_plugins_string = config.get(section, plugin_type).strip()
+ plugin_type_list = getattr(local_plugins, plugin_type)
+ plugin_type_list.extend(utils.parse_comma_separated_list(
+ local_plugins_string,
+ regexp=utils.LOCAL_PLUGIN_LIST_RE,
+ ))
+ return local_plugins
+
+
+LocalPlugins = collections.namedtuple('LocalPlugins', 'extension report')
diff --git a/src/flake8/options/manager.py b/src/flake8/options/manager.py
index 7b23732..5b4796f 100644
--- a/src/flake8/options/manager.py
+++ b/src/flake8/options/manager.py
@@ -1,4 +1,5 @@
"""Option handling and Option management logic."""
+import collections
import logging
import optparse # pylint: disable=deprecated-module
@@ -153,6 +154,10 @@ class Option(object):
return self._opt
+PluginVersion = collections.namedtuple("PluginVersion",
+ ["name", "version", "local"])
+
+
class OptionManager(object):
"""Manage Options and OptionParser while adding post-processing."""
@@ -178,9 +183,9 @@ class OptionManager(object):
self.extended_default_select = set()
@staticmethod
- def format_plugin(plugin_tuple):
- """Convert a plugin tuple into a dictionary mapping name to value."""
- return dict(zip(["name", "version"], plugin_tuple))
+ def format_plugin(plugin):
+ """Convert a PluginVersion into a dictionary mapping name to value."""
+ return {attr: getattr(plugin, attr) for attr in ["name", "version"]}
def add_option(self, *args, **kwargs):
"""Create and register a new option.
@@ -306,7 +311,7 @@ class OptionManager(object):
self._normalize(options)
return options, xargs
- def register_plugin(self, name, version):
+ def register_plugin(self, name, version, local=False):
"""Register a plugin relying on the OptionManager.
:param str name:
@@ -314,5 +319,7 @@ class OptionManager(object):
attribute of the class or function loaded from the entry-point.
:param str version:
The version of the checker that we're using.
+ :param bool local:
+ Whether the plugin is local to the project/repository or not.
"""
- self.registered_plugins.add((name, version))
+ self.registered_plugins.add(PluginVersion(name, version, local))
diff --git a/src/flake8/plugins/manager.py b/src/flake8/plugins/manager.py
index 80a9ef2..503dfbb 100644
--- a/src/flake8/plugins/manager.py
+++ b/src/flake8/plugins/manager.py
@@ -24,7 +24,7 @@ NO_GROUP_FOUND = object()
class Plugin(object):
"""Wrap an EntryPoint from setuptools and other logic."""
- def __init__(self, name, entry_point):
+ def __init__(self, name, entry_point, local=False):
"""Initialize our Plugin.
:param str name:
@@ -33,9 +33,12 @@ class Plugin(object):
EntryPoint returned by setuptools.
:type entry_point:
setuptools.EntryPoint
+ :param bool local:
+ Is this a repo-local plugin?
"""
self.name = name
self.entry_point = entry_point
+ self.local = local
self._plugin = None
self._parameters = None
self._parameter_names = None
@@ -236,11 +239,14 @@ class Plugin(object):
class PluginManager(object): # pylint: disable=too-few-public-methods
"""Find and manage plugins consistently."""
- def __init__(self, namespace, verify_requirements=False):
+ def __init__(self, namespace,
+ verify_requirements=False, local_plugins=None):
"""Initialize the manager.
:param str namespace:
Namespace of the plugins to manage, e.g., 'flake8.extension'.
+ :param list local_plugins:
+ Plugins from config (as "X = path.to:Plugin" strings).
:param bool verify_requirements:
Whether or not to make setuptools verify that the requirements for
the plugin are satisfied.
@@ -249,15 +255,36 @@ class PluginManager(object): # pylint: disable=too-few-public-methods
self.verify_requirements = verify_requirements
self.plugins = {}
self.names = []
- self._load_all_plugins()
+ self._load_local_plugins(local_plugins or [])
+ self._load_entrypoint_plugins()
- def _load_all_plugins(self):
+ def _load_local_plugins(self, local_plugins):
+ """Load local plugins from config.
+
+ :param list local_plugins:
+ Plugins from config (as "X = path.to:Plugin" strings).
+ """
+ for plugin_str in local_plugins:
+ entry_point = pkg_resources.EntryPoint.parse(plugin_str)
+ self._load_plugin_from_entrypoint(entry_point, local=True)
+
+ def _load_entrypoint_plugins(self):
LOG.info('Loading entry-points for "%s".', self.namespace)
for entry_point in pkg_resources.iter_entry_points(self.namespace):
- name = entry_point.name
- self.plugins[name] = Plugin(name, entry_point)
- self.names.append(name)
- LOG.debug('Loaded %r for plugin "%s".', self.plugins[name], name)
+ self._load_plugin_from_entrypoint(entry_point)
+
+ def _load_plugin_from_entrypoint(self, entry_point, local=False):
+ """Load a plugin from a setuptools EntryPoint.
+
+ :param EntryPoint entry_point:
+ EntryPoint to load plugin from.
+ :param bool local:
+ Is this a repo-local plugin?
+ """
+ name = entry_point.name
+ self.plugins[name] = Plugin(name, entry_point, local=local)
+ self.names.append(name)
+ LOG.debug('Loaded %r for plugin "%s".', self.plugins[name], name)
def map(self, func, *args, **kwargs):
r"""Call ``func`` with the plugin and \*args and \**kwargs after.
@@ -329,9 +356,14 @@ class PluginTypeManager(object):
... 867 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-flake8.git
More information about the Python-modules-commits
mailing list