mirror of
https://github.com/PyCQA/flake8.git
synced 2026-04-12 23:54:17 +00:00
Merge branch 'py3_plus' into 'master'
drop legacy python versions Closes #690 See merge request pycqa/flake8!471
This commit is contained in:
commit
e0116d8e77
65 changed files with 629 additions and 731 deletions
|
|
@ -1,8 +1,8 @@
|
||||||
# To activate, change the Appveyor settings to use `.appveyor.yml`.
|
# To activate, change the Appveyor settings to use `.appveyor.yml`.
|
||||||
install:
|
install:
|
||||||
- python -m pip install --upgrade setuptools tox virtualenv
|
- C:\Python38-x64\python.exe -m pip install --upgrade setuptools tox virtualenv
|
||||||
|
|
||||||
build: off
|
build: off
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- python -m tox -e py27,py36,py37,dogfood
|
- C:\Python38-x64\python.exe -m tox -e py36,py37,dogfood
|
||||||
|
|
|
||||||
|
|
@ -30,3 +30,4 @@ exclude_lines =
|
||||||
# Don't complain if non-runnable code isn't run:
|
# Don't complain if non-runnable code isn't run:
|
||||||
^if __name__ == ['"]__main__['"]:$
|
^if __name__ == ['"]__main__['"]:$
|
||||||
^\s*if False:
|
^\s*if False:
|
||||||
|
^\s*if TYPE_CHECKING:
|
||||||
|
|
|
||||||
|
|
@ -13,26 +13,11 @@ after_script:
|
||||||
- pip install codecov
|
- pip install codecov
|
||||||
- codecov --token=7d117e6b-aab6-4283-ab19-166dafc38cf5
|
- codecov --token=7d117e6b-aab6-4283-ab19-166dafc38cf5
|
||||||
|
|
||||||
pypy2:
|
|
||||||
image: pypy:2.7-7.2.0
|
|
||||||
stage: test
|
|
||||||
script: tox -e pypy
|
|
||||||
|
|
||||||
pypy3:
|
pypy3:
|
||||||
image: pypy:3.6-7.2.0
|
image: pypy:3.6-7.2.0
|
||||||
stage: test
|
stage: test
|
||||||
script: tox -e pypy3
|
script: tox -e pypy3
|
||||||
|
|
||||||
python2:
|
|
||||||
image: python:2.7
|
|
||||||
stage: test
|
|
||||||
script: tox -e py27
|
|
||||||
|
|
||||||
python35:
|
|
||||||
image: python:3.5
|
|
||||||
stage: test
|
|
||||||
script: tox -e py35
|
|
||||||
|
|
||||||
python36:
|
python36:
|
||||||
image: python:3.6
|
image: python:3.6
|
||||||
stage: test
|
stage: test
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
exclude: ^tests/fixtures/example-code/
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v2.3.0
|
rev: v2.3.0
|
||||||
|
|
@ -7,12 +8,22 @@ repos:
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
exclude: ^tests/fixtures/diffs/
|
exclude: ^tests/fixtures/diffs/
|
||||||
|
- repo: https://github.com/asottile/reorder_python_imports
|
||||||
|
rev: v2.4.0
|
||||||
|
hooks:
|
||||||
|
- id: reorder-python-imports
|
||||||
|
args: [--application-directories, '.:src', --py36-plus]
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 20.8b1
|
rev: 20.8b1
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
args: [--line-length=78]
|
args: [--line-length=78]
|
||||||
files: ^src/
|
files: ^src/
|
||||||
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
|
rev: v2.11.0
|
||||||
|
hooks:
|
||||||
|
- id: pyupgrade
|
||||||
|
args: [--py36-plus]
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v0.720
|
rev: v0.720
|
||||||
hooks:
|
hooks:
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,12 @@ notifications:
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- python: 2.7
|
|
||||||
env: TOXENV=py27
|
|
||||||
- python: 3.5
|
|
||||||
env: TOXENV=py35
|
|
||||||
- python: 3.6
|
- python: 3.6
|
||||||
env: TOXENV=py36
|
env: TOXENV=py36
|
||||||
- python: 3.7
|
- python: 3.7
|
||||||
env: TOXENV=py37
|
env: TOXENV=py37
|
||||||
- python: 3.8
|
- python: 3.8
|
||||||
env: TOXENV=py38
|
env: TOXENV=py38
|
||||||
- python: pypy
|
|
||||||
env: TOXENV=pypy
|
|
||||||
- python: 3.7
|
- python: 3.7
|
||||||
env: TOXENV=readme
|
env: TOXENV=readme
|
||||||
- python: 3.7
|
- python: 3.7
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# flake8 documentation build configuration file, created by
|
# flake8 documentation build configuration file, created by
|
||||||
# sphinx-quickstart on Tue Jan 19 07:14:10 2016.
|
# sphinx-quickstart on Tue Jan 19 07:14:10 2016.
|
||||||
|
|
@ -11,9 +10,8 @@
|
||||||
#
|
#
|
||||||
# All configuration values have a default; values that are commented out
|
# All configuration values have a default; values that are commented out
|
||||||
# serve to show the default.
|
# serve to show the default.
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
|
@ -53,11 +51,12 @@ source_suffix = '.rst'
|
||||||
master_doc = 'index'
|
master_doc = 'index'
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'flake8'
|
project = 'flake8'
|
||||||
copyright = u'2016, Ian Stapleton Cordasco'
|
copyright = '2016, Ian Stapleton Cordasco'
|
||||||
author = u'Ian Stapleton Cordasco'
|
author = 'Ian Stapleton Cordasco'
|
||||||
|
|
||||||
import flake8
|
import flake8
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
# built documents.
|
# built documents.
|
||||||
|
|
@ -234,8 +233,8 @@ latex_elements = {
|
||||||
# (source start file, target name, title,
|
# (source start file, target name, title,
|
||||||
# author, documentclass [howto, manual, or own class]).
|
# author, documentclass [howto, manual, or own class]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
(master_doc, 'flake8.tex', u'flake8 Documentation',
|
(master_doc, 'flake8.tex', 'flake8 Documentation',
|
||||||
u'Ian Stapleton Cordasco', 'manual'),
|
'Ian Stapleton Cordasco', 'manual'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
|
|
@ -264,7 +263,7 @@ latex_documents = [
|
||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [
|
||||||
('manpage', 'flake8', u'Flake8 Command Line Documentation',
|
('manpage', 'flake8', 'Flake8 Command Line Documentation',
|
||||||
[author], 1)
|
[author], 1)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -278,7 +277,7 @@ man_pages = [
|
||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
('index', 'Flake8', u'Flake8 Documentation', u'Tarek Ziade',
|
('index', 'Flake8', 'Flake8 Documentation', 'Tarek Ziade',
|
||||||
'Flake8', 'Code checking using pycodestyle, pyflakes and mccabe',
|
'Flake8', 'Code checking using pycodestyle, pyflakes and mccabe',
|
||||||
'Miscellaneous'),
|
'Miscellaneous'),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -81,13 +81,11 @@ for users.
|
||||||
|
|
||||||
Before releasing, the following tox test environments must pass:
|
Before releasing, the following tox test environments must pass:
|
||||||
|
|
||||||
- Python 2.7 (a.k.a., ``tox -e py27``)
|
|
||||||
|
|
||||||
- Python 3.6 (a.k.a., ``tox -e py36``)
|
- Python 3.6 (a.k.a., ``tox -e py36``)
|
||||||
|
|
||||||
- Python 3.7 (a.k.a., ``tox -e py37``)
|
- Python 3.7 (a.k.a., ``tox -e py37``)
|
||||||
|
|
||||||
- PyPy (a.k.a., ``tox -e pypy``)
|
- PyPy 3 (a.k.a., ``tox -e pypy3``)
|
||||||
|
|
||||||
- Linters (a.k.a., ``tox -e linters``)
|
- Linters (a.k.a., ``tox -e linters``)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,11 +175,7 @@ across multiple lines, insert a new-line after the opening parenthesis, e.g.,
|
||||||
statistic = next(stats_for_error_code)
|
statistic = next(stats_for_error_code)
|
||||||
count = statistic.count
|
count = statistic.count
|
||||||
count += sum(stat.count for stat in stats_for_error_code)
|
count += sum(stat.count for stat in stats_for_error_code)
|
||||||
self._write('{count:<5} {error_code} {message}'.format(
|
self._write(f'{count:<5} {error_code} {statistic.message}')
|
||||||
count=count,
|
|
||||||
error_code=error_code,
|
|
||||||
message=statistic.message,
|
|
||||||
))
|
|
||||||
|
|
||||||
In the first example, we put a few of the parameters all on one line, and then
|
In the first example, we put a few of the parameters all on one line, and then
|
||||||
added the last two on their own. In the second example, each parameter has its
|
added the last two on their own. In the second example, each parameter has its
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ like:
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"License :: OSI Approved :: MIT License",
|
"License :: OSI Approved :: MIT License",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 2",
|
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||||
"Topic :: Software Development :: Quality Assurance",
|
"Topic :: Software Development :: Quality Assurance",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
sphinx>=1.3.0,!=3.1.0
|
sphinx>=1.3.0,!=3.1.0
|
||||||
sphinx_rtd_theme
|
sphinx_rtd_theme
|
||||||
sphinx-prompt
|
sphinx-prompt
|
||||||
configparser
|
|
||||||
flake8-polyfill
|
flake8-polyfill
|
||||||
|
|
|
||||||
|
|
@ -100,8 +100,6 @@ generates its own :term:`error code`\ s for ``pyflakes``:
|
||||||
+------+---------------------------------------------------------------------+
|
+------+---------------------------------------------------------------------+
|
||||||
| F811 | redefinition of unused ``name`` from line ``N`` |
|
| F811 | redefinition of unused ``name`` from line ``N`` |
|
||||||
+------+---------------------------------------------------------------------+
|
+------+---------------------------------------------------------------------+
|
||||||
| F812 | list comprehension redefines ``name`` from line ``N`` |
|
|
||||||
+------+---------------------------------------------------------------------+
|
|
||||||
| F821 | undefined name ``name`` |
|
| F821 | undefined name ``name`` |
|
||||||
+------+---------------------------------------------------------------------+
|
+------+---------------------------------------------------------------------+
|
||||||
| F822 | undefined name ``name`` in ``__all__`` |
|
| F822 | undefined name ``name`` in ``__all__`` |
|
||||||
|
|
@ -116,9 +114,6 @@ generates its own :term:`error code`\ s for ``pyflakes``:
|
||||||
| F901 | ``raise NotImplemented`` should be ``raise NotImplementedError`` |
|
| F901 | ``raise NotImplemented`` should be ``raise NotImplementedError`` |
|
||||||
+------+---------------------------------------------------------------------+
|
+------+---------------------------------------------------------------------+
|
||||||
|
|
||||||
Note that some of these entries behave differently on Python 2 and Python 3,
|
|
||||||
for example F812 is specific to Python 2 only.
|
|
||||||
|
|
||||||
We also report one extra error: ``E999``. We report ``E999`` when we fail to
|
We also report one extra error: ``E999``. We report ``E999`` when we fail to
|
||||||
compile a file into an Abstract Syntax Tree for the plugins that require it.
|
compile a file into an Abstract Syntax Tree for the plugins that require it.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,25 +14,25 @@ like so:
|
||||||
|
|
||||||
Where you simply allow the shell running in your terminal to locate |Flake8|.
|
Where you simply allow the shell running in your terminal to locate |Flake8|.
|
||||||
In some cases, though, you may have installed |Flake8| for multiple versions
|
In some cases, though, you may have installed |Flake8| for multiple versions
|
||||||
of Python (e.g., Python 2.7 and Python 3.5) and you need to call a specific
|
of Python (e.g., Python 3.8 and Python 3.9) and you need to call a specific
|
||||||
version. In that case, you will have much better results using:
|
version. In that case, you will have much better results using:
|
||||||
|
|
||||||
.. prompt:: bash
|
.. prompt:: bash
|
||||||
|
|
||||||
python2.7 -m flake8
|
python3.8 -m flake8
|
||||||
|
|
||||||
Or
|
Or
|
||||||
|
|
||||||
.. prompt:: bash
|
.. prompt:: bash
|
||||||
|
|
||||||
python3.5 -m flake8
|
python3.9 -m flake8
|
||||||
|
|
||||||
Since that will tell the correct version of Python to run |Flake8|.
|
Since that will tell the correct version of Python to run |Flake8|.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Installing |Flake8| once will not install it on both Python 2.7 and
|
Installing |Flake8| once will not install it on both Python 3.8 and
|
||||||
Python 3.5. It will only install it for the version of Python that
|
Python 3.9. It will only install it for the version of Python that
|
||||||
is running pip.
|
is running pip.
|
||||||
|
|
||||||
It is also possible to specify command-line options directly to |Flake8|:
|
It is also possible to specify command-line options directly to |Flake8|:
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,8 @@ appropriate of:
|
||||||
pip install <plugin-name>
|
pip install <plugin-name>
|
||||||
pip3 install <plugin-name>
|
pip3 install <plugin-name>
|
||||||
python -m pip install <plugin-name>
|
python -m pip install <plugin-name>
|
||||||
python2.7 -m pip install <plugin-name>
|
|
||||||
python3 -m pip install <plugin-name>
|
python3 -m pip install <plugin-name>
|
||||||
python3.4 -m pip install <plugin-name>
|
python3.9 -m pip install <plugin-name>
|
||||||
python3.5 -m pip install <plugin-name>
|
|
||||||
|
|
||||||
To install the plugin, where ``<plugin-name>`` is the package name on PyPI_.
|
To install the plugin, where ``<plugin-name>`` is the package name on PyPI_.
|
||||||
To verify installation use:
|
To verify installation use:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import setuptools
|
import setuptools
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
|
|
@ -21,11 +20,9 @@ setuptools.setup(
|
||||||
'Framework :: Flake8',
|
'Framework :: Flake8',
|
||||||
'License :: OSI Approved :: MIT License',
|
'License :: OSI Approved :: MIT License',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
'Programming Language :: Python :: 2',
|
|
||||||
'Programming Language :: Python :: 2.7',
|
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.4',
|
'Programming Language :: Python :: 3.8',
|
||||||
'Programming Language :: Python :: 3.5',
|
'Programming Language :: Python :: 3.9',
|
||||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||||
'Topic :: Software Development :: Quality Assurance',
|
'Topic :: Software Development :: Quality Assurance',
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
"""Module for an example Flake8 plugin."""
|
"""Module for an example Flake8 plugin."""
|
||||||
|
|
||||||
from .on_by_default import ExampleOne
|
|
||||||
from .off_by_default import ExampleTwo
|
from .off_by_default import ExampleTwo
|
||||||
|
from .on_by_default import ExampleOne
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ExampleOne',
|
'ExampleOne',
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""Our first example plugin."""
|
"""Our first example plugin."""
|
||||||
|
|
||||||
|
|
||||||
class ExampleTwo(object):
|
class ExampleTwo:
|
||||||
"""Second Example Plugin."""
|
"""Second Example Plugin."""
|
||||||
name = 'off-by-default-example-plugin'
|
name = 'off-by-default-example-plugin'
|
||||||
version = '1.0.0'
|
version = '1.0.0'
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""Our first example plugin."""
|
"""Our first example plugin."""
|
||||||
|
|
||||||
|
|
||||||
class ExampleOne(object):
|
class ExampleOne:
|
||||||
"""First Example Plugin."""
|
"""First Example Plugin."""
|
||||||
name = 'on-by-default-example-plugin'
|
name = 'on-by-default-example-plugin'
|
||||||
version = '1.0.0'
|
version = '1.0.0'
|
||||||
|
|
@ -11,5 +11,4 @@ class ExampleOne(object):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Do nothing."""
|
"""Do nothing."""
|
||||||
for message in []:
|
yield from []
|
||||||
yield message
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,4 @@
|
||||||
[pytest]
|
[pytest]
|
||||||
norecursedirs = .git .* *.egg* old docs dist build
|
norecursedirs = .git .* *.egg* old docs dist build
|
||||||
addopts = -rw
|
addopts = -rw
|
||||||
filterwarnings =
|
filterwarnings = error
|
||||||
error
|
|
||||||
# python3.4 raises this when importing setuptools
|
|
||||||
ignore:The value of convert_charrefs will become True in 3.5.*:DeprecationWarning
|
|
||||||
# python3 raises this when importing setuptools
|
|
||||||
ignore:the imp module is deprecated in favour of importlib.*:PendingDeprecationWarning
|
|
||||||
ignore:the imp module is deprecated in favour of importlib.*:DeprecationWarning
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,7 @@ classifiers =
|
||||||
Intended Audience :: Developers
|
Intended Audience :: Developers
|
||||||
License :: OSI Approved :: MIT License
|
License :: OSI Approved :: MIT License
|
||||||
Programming Language :: Python
|
Programming Language :: Python
|
||||||
Programming Language :: Python :: 2
|
|
||||||
Programming Language :: Python :: 2.7
|
|
||||||
Programming Language :: Python :: 3
|
Programming Language :: Python :: 3
|
||||||
Programming Language :: Python :: 3.5
|
|
||||||
Programming Language :: Python :: 3.6
|
Programming Language :: Python :: 3.6
|
||||||
Programming Language :: Python :: 3.7
|
Programming Language :: Python :: 3.7
|
||||||
Programming Language :: Python :: 3.8
|
Programming Language :: Python :: 3.8
|
||||||
|
|
@ -44,13 +41,9 @@ install_requires=
|
||||||
pyflakes >= 2.3.0, < 2.4.0
|
pyflakes >= 2.3.0, < 2.4.0
|
||||||
pycodestyle >= 2.7.0, < 2.8.0
|
pycodestyle >= 2.7.0, < 2.8.0
|
||||||
mccabe >= 0.6.0, < 0.7.0
|
mccabe >= 0.6.0, < 0.7.0
|
||||||
enum34; python_version<"3.4"
|
|
||||||
typing; python_version<"3.5"
|
|
||||||
configparser; python_version<"3.2"
|
|
||||||
functools32; python_version<"3.2"
|
|
||||||
importlib-metadata; python_version<"3.8"
|
importlib-metadata; python_version<"3.8"
|
||||||
|
|
||||||
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
|
python_requires = >=3.6
|
||||||
|
|
||||||
[options.packages.find]
|
[options.packages.find]
|
||||||
where = src
|
where = src
|
||||||
|
|
|
||||||
1
setup.py
1
setup.py
|
|
@ -1,4 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""Packaging logic for Flake8."""
|
"""Packaging logic for Flake8."""
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,7 @@ This module
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Type
|
||||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
|
||||||
from typing import Type # `typing.Type` was introduced in 3.5.2
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
LOG.addHandler(logging.NullHandler())
|
LOG.addHandler(logging.NullHandler())
|
||||||
|
|
@ -64,7 +62,7 @@ def configure_logging(verbosity, filename=None, logformat=LOG_FORMAT):
|
||||||
|
|
||||||
if not filename or filename in ("stderr", "stdout"):
|
if not filename or filename in ("stderr", "stdout"):
|
||||||
fileobj = getattr(sys, filename or "stderr")
|
fileobj = getattr(sys, filename or "stderr")
|
||||||
handler_cls = logging.StreamHandler # type: Type[logging.Handler]
|
handler_cls: Type[logging.Handler] = logging.StreamHandler
|
||||||
else:
|
else:
|
||||||
fileobj = filename
|
fileobj = filename
|
||||||
handler_cls = logging.FileHandler
|
handler_cls = logging.FileHandler
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,9 @@
|
||||||
"""Expose backports in a single place."""
|
"""Expose backports in a single place."""
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if sys.version_info >= (3,): # pragma: no cover (PY3+)
|
|
||||||
from functools import lru_cache
|
|
||||||
else: # pragma: no cover (<PY3)
|
|
||||||
from functools32 import lru_cache
|
|
||||||
|
|
||||||
if sys.version_info >= (3, 8): # pragma: no cover (PY38+)
|
if sys.version_info >= (3, 8): # pragma: no cover (PY38+)
|
||||||
import importlib.metadata as importlib_metadata
|
import importlib.metadata as importlib_metadata
|
||||||
else: # pragma: no cover (<PY38)
|
else: # pragma: no cover (<PY38)
|
||||||
import importlib_metadata
|
import importlib_metadata
|
||||||
|
|
||||||
__all__ = ("lru_cache", "importlib_metadata")
|
__all__ = ("importlib_metadata",)
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ def get_style_guide(**kwargs):
|
||||||
return StyleGuide(application)
|
return StyleGuide(application)
|
||||||
|
|
||||||
|
|
||||||
class StyleGuide(object):
|
class StyleGuide:
|
||||||
"""Public facing object that mimic's Flake8 2.0's StyleGuide.
|
"""Public facing object that mimic's Flake8 2.0's StyleGuide.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
@ -81,7 +81,7 @@ class StyleGuide(object):
|
||||||
self._file_checker_manager = application.file_checker_manager
|
self._file_checker_manager = application.file_checker_manager
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def options(self): # type: () -> argparse.Namespace
|
def options(self) -> argparse.Namespace:
|
||||||
"""Return application's options.
|
"""Return application's options.
|
||||||
|
|
||||||
An instance of :class:`argparse.Namespace` containing parsed options.
|
An instance of :class:`argparse.Namespace` containing parsed options.
|
||||||
|
|
@ -170,7 +170,7 @@ class StyleGuide(object):
|
||||||
return self.check_files([filename])
|
return self.check_files([filename])
|
||||||
|
|
||||||
|
|
||||||
class Report(object):
|
class Report:
|
||||||
"""Public facing object that mimic's Flake8 2.0's API.
|
"""Public facing object that mimic's Flake8 2.0's API.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
@ -210,6 +210,6 @@ class Report(object):
|
||||||
list
|
list
|
||||||
"""
|
"""
|
||||||
return [
|
return [
|
||||||
"{} {} {}".format(s.count, s.error_code, s.message)
|
f"{s.count} {s.error_code} {s.message}"
|
||||||
for s in self._stats.statistics_for(violation)
|
for s in self._stats.statistics_for(violation)
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,22 @@ import errno
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
import signal
|
import signal
|
||||||
import sys
|
|
||||||
import tokenize
|
import tokenize
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
try:
|
from typing import Optional
|
||||||
import multiprocessing.pool
|
from typing import Tuple
|
||||||
except ImportError:
|
|
||||||
multiprocessing = None # type: ignore
|
|
||||||
|
|
||||||
from flake8 import defaults
|
from flake8 import defaults
|
||||||
from flake8 import exceptions
|
from flake8 import exceptions
|
||||||
from flake8 import processor
|
from flake8 import processor
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
|
|
||||||
|
try:
|
||||||
|
import multiprocessing.pool
|
||||||
|
except ImportError:
|
||||||
|
multiprocessing = None # type: ignore
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
SERIAL_RETRY_ERRNOS = {
|
SERIAL_RETRY_ERRNOS = {
|
||||||
|
|
@ -38,17 +40,14 @@ SERIAL_RETRY_ERRNOS = {
|
||||||
|
|
||||||
def _multiprocessing_is_fork(): # type () -> bool
|
def _multiprocessing_is_fork(): # type () -> bool
|
||||||
"""Class state is only preserved when using the `fork` strategy."""
|
"""Class state is only preserved when using the `fork` strategy."""
|
||||||
if sys.version_info >= (3, 4):
|
return (
|
||||||
return (
|
multiprocessing
|
||||||
multiprocessing
|
# https://github.com/python/typeshed/pull/3415
|
||||||
# https://github.com/python/typeshed/pull/3415
|
and multiprocessing.get_start_method() == "fork" # type: ignore
|
||||||
and multiprocessing.get_start_method() == "fork" # type: ignore
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
return multiprocessing and not utils.is_windows()
|
|
||||||
|
|
||||||
|
|
||||||
class Manager(object):
|
class Manager:
|
||||||
"""Manage the parallelism and checker instances for each plugin and file.
|
"""Manage the parallelism and checker instances for each plugin and file.
|
||||||
|
|
||||||
This class will be responsible for the following:
|
This class will be responsible for the following:
|
||||||
|
|
@ -86,8 +85,8 @@ class Manager(object):
|
||||||
self.options = style_guide.options
|
self.options = style_guide.options
|
||||||
self.checks = checker_plugins
|
self.checks = checker_plugins
|
||||||
self.jobs = self._job_count()
|
self.jobs = self._job_count()
|
||||||
self._all_checkers = [] # type: List[FileChecker]
|
self._all_checkers: List[FileChecker] = []
|
||||||
self.checkers = [] # type: List[FileChecker]
|
self.checkers: List[FileChecker] = []
|
||||||
self.statistics = {
|
self.statistics = {
|
||||||
"files": 0,
|
"files": 0,
|
||||||
"logical lines": 0,
|
"logical lines": 0,
|
||||||
|
|
@ -104,8 +103,7 @@ class Manager(object):
|
||||||
self.statistics[statistic] += checker.statistics[statistic]
|
self.statistics[statistic] += checker.statistics[statistic]
|
||||||
self.statistics["files"] += len(self.checkers)
|
self.statistics["files"] += len(self.checkers)
|
||||||
|
|
||||||
def _job_count(self):
|
def _job_count(self) -> int:
|
||||||
# type: () -> int
|
|
||||||
# First we walk through all of our error cases:
|
# First we walk through all of our error cases:
|
||||||
# - multiprocessing library is not present
|
# - multiprocessing library is not present
|
||||||
# - we're running on windows in which case we know we have significant
|
# - we're running on windows in which case we know we have significant
|
||||||
|
|
@ -166,8 +164,7 @@ class Manager(object):
|
||||||
)
|
)
|
||||||
return reported_results_count
|
return reported_results_count
|
||||||
|
|
||||||
def is_path_excluded(self, path):
|
def is_path_excluded(self, path: str) -> bool:
|
||||||
# type: (str) -> bool
|
|
||||||
"""Check if a path is excluded.
|
"""Check if a path is excluded.
|
||||||
|
|
||||||
:param str path:
|
:param str path:
|
||||||
|
|
@ -190,8 +187,7 @@ class Manager(object):
|
||||||
logger=LOG,
|
logger=LOG,
|
||||||
)
|
)
|
||||||
|
|
||||||
def make_checkers(self, paths=None):
|
def make_checkers(self, paths: Optional[List[str]] = None) -> None:
|
||||||
# type: (Optional[List[str]]) -> None
|
|
||||||
"""Create checkers for each file."""
|
"""Create checkers for each file."""
|
||||||
if paths is None:
|
if paths is None:
|
||||||
paths = self.arguments
|
paths = self.arguments
|
||||||
|
|
@ -236,8 +232,7 @@ class Manager(object):
|
||||||
self.checkers = [c for c in self._all_checkers if c.should_process]
|
self.checkers = [c for c in self._all_checkers if c.should_process]
|
||||||
LOG.info("Checking %d files", len(self.checkers))
|
LOG.info("Checking %d files", len(self.checkers))
|
||||||
|
|
||||||
def report(self):
|
def report(self) -> Tuple[int, int]:
|
||||||
# type: () -> Tuple[int, int]
|
|
||||||
"""Report all of the errors found in the managed file checkers.
|
"""Report all of the errors found in the managed file checkers.
|
||||||
|
|
||||||
This iterates over each of the checkers and reports the errors sorted
|
This iterates over each of the checkers and reports the errors sorted
|
||||||
|
|
@ -259,11 +254,11 @@ class Manager(object):
|
||||||
results_found += len(results)
|
results_found += len(results)
|
||||||
return (results_found, results_reported)
|
return (results_found, results_reported)
|
||||||
|
|
||||||
def run_parallel(self): # type: () -> None
|
def run_parallel(self) -> None:
|
||||||
"""Run the checkers in parallel."""
|
"""Run the checkers in parallel."""
|
||||||
# fmt: off
|
# fmt: off
|
||||||
final_results = collections.defaultdict(list) # type: Dict[str, List[Tuple[str, int, int, str, Optional[str]]]] # noqa: E501
|
final_results: Dict[str, List[Tuple[str, int, int, str, Optional[str]]]] = collections.defaultdict(list) # noqa: E501
|
||||||
final_statistics = collections.defaultdict(dict) # type: Dict[str, Dict[str, int]] # noqa: E501
|
final_statistics: Dict[str, Dict[str, int]] = collections.defaultdict(dict) # noqa: E501
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
pool = _try_initialize_processpool(self.jobs)
|
pool = _try_initialize_processpool(self.jobs)
|
||||||
|
|
@ -298,12 +293,12 @@ class Manager(object):
|
||||||
checker.results = final_results[filename]
|
checker.results = final_results[filename]
|
||||||
checker.statistics = final_statistics[filename]
|
checker.statistics = final_statistics[filename]
|
||||||
|
|
||||||
def run_serial(self): # type: () -> None
|
def run_serial(self) -> None:
|
||||||
"""Run the checkers in serial."""
|
"""Run the checkers in serial."""
|
||||||
for checker in self.checkers:
|
for checker in self.checkers:
|
||||||
checker.run_checks()
|
checker.run_checks()
|
||||||
|
|
||||||
def run(self): # type: () -> None
|
def run(self) -> None:
|
||||||
"""Run all the checkers.
|
"""Run all the checkers.
|
||||||
|
|
||||||
This will intelligently decide whether to run the checks in parallel
|
This will intelligently decide whether to run the checks in parallel
|
||||||
|
|
@ -337,7 +332,7 @@ class Manager(object):
|
||||||
self._process_statistics()
|
self._process_statistics()
|
||||||
|
|
||||||
|
|
||||||
class FileChecker(object):
|
class FileChecker:
|
||||||
"""Manage running checks for a file and aggregate the results."""
|
"""Manage running checks for a file and aggregate the results."""
|
||||||
|
|
||||||
def __init__(self, filename, checks, options):
|
def __init__(self, filename, checks, options):
|
||||||
|
|
@ -357,9 +352,7 @@ class FileChecker(object):
|
||||||
self.options = options
|
self.options = options
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.checks = checks
|
self.checks = checks
|
||||||
# fmt: off
|
self.results: List[Tuple[str, int, int, str, Optional[str]]] = []
|
||||||
self.results = [] # type: List[Tuple[str, int, int, str, Optional[str]]] # noqa: E501
|
|
||||||
# fmt: on
|
|
||||||
self.statistics = {
|
self.statistics = {
|
||||||
"tokens": 0,
|
"tokens": 0,
|
||||||
"logical lines": 0,
|
"logical lines": 0,
|
||||||
|
|
@ -373,27 +366,30 @@ class FileChecker(object):
|
||||||
self.should_process = not self.processor.should_ignore_file()
|
self.should_process = not self.processor.should_ignore_file()
|
||||||
self.statistics["physical lines"] = len(self.processor.lines)
|
self.statistics["physical lines"] = len(self.processor.lines)
|
||||||
|
|
||||||
def __repr__(self): # type: () -> str
|
def __repr__(self) -> str:
|
||||||
"""Provide helpful debugging representation."""
|
"""Provide helpful debugging representation."""
|
||||||
return "FileChecker for {}".format(self.filename)
|
return f"FileChecker for {self.filename}"
|
||||||
|
|
||||||
def _make_processor(self):
|
def _make_processor(self) -> Optional[processor.FileProcessor]:
|
||||||
# type: () -> Optional[processor.FileProcessor]
|
|
||||||
try:
|
try:
|
||||||
return processor.FileProcessor(self.filename, self.options)
|
return processor.FileProcessor(self.filename, self.options)
|
||||||
except IOError as e:
|
except OSError as e:
|
||||||
# If we can not read the file due to an IOError (e.g., the file
|
# If we can not read the file due to an IOError (e.g., the file
|
||||||
# does not exist or we do not have the permissions to open it)
|
# does not exist or we do not have the permissions to open it)
|
||||||
# then we need to format that exception for the user.
|
# then we need to format that exception for the user.
|
||||||
# NOTE(sigmavirus24): Historically, pep8 has always reported this
|
# NOTE(sigmavirus24): Historically, pep8 has always reported this
|
||||||
# as an E902. We probably *want* a better error code for this
|
# as an E902. We probably *want* a better error code for this
|
||||||
# going forward.
|
# going forward.
|
||||||
message = "{0}: {1}".format(type(e).__name__, e)
|
self.report("E902", 0, 0, f"{type(e).__name__}: {e}")
|
||||||
self.report("E902", 0, 0, message)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def report(self, error_code, line_number, column, text):
|
def report(
|
||||||
# type: (Optional[str], int, int, str) -> str
|
self,
|
||||||
|
error_code: Optional[str],
|
||||||
|
line_number: int,
|
||||||
|
column: int,
|
||||||
|
text: str,
|
||||||
|
) -> str:
|
||||||
"""Report an error by storing it in the results list."""
|
"""Report an error by storing it in the results list."""
|
||||||
if error_code is None:
|
if error_code is None:
|
||||||
error_code, text = text.split(" ", 1)
|
error_code, text = text.split(" ", 1)
|
||||||
|
|
@ -469,14 +465,14 @@ class FileChecker(object):
|
||||||
column -= column_offset
|
column -= column_offset
|
||||||
return row, column
|
return row, column
|
||||||
|
|
||||||
def run_ast_checks(self): # type: () -> None
|
def run_ast_checks(self) -> None:
|
||||||
"""Run all checks expecting an abstract syntax tree."""
|
"""Run all checks expecting an abstract syntax tree."""
|
||||||
try:
|
try:
|
||||||
ast = self.processor.build_ast()
|
ast = self.processor.build_ast()
|
||||||
except (ValueError, SyntaxError, TypeError) as e:
|
except (ValueError, SyntaxError, TypeError) as e:
|
||||||
row, column = self._extract_syntax_information(e)
|
row, column = self._extract_syntax_information(e)
|
||||||
self.report(
|
self.report(
|
||||||
"E999", row, column, "%s: %s" % (type(e).__name__, e.args[0])
|
"E999", row, column, f"{type(e).__name__}: {e.args[0]}"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -608,8 +604,9 @@ class FileChecker(object):
|
||||||
else:
|
else:
|
||||||
self.run_logical_checks()
|
self.run_logical_checks()
|
||||||
|
|
||||||
def check_physical_eol(self, token, prev_physical):
|
def check_physical_eol(
|
||||||
# type: (processor._Token, str) -> None
|
self, token: processor._Token, prev_physical: str
|
||||||
|
) -> None:
|
||||||
"""Run physical checks if and only if it is at the end of the line."""
|
"""Run physical checks if and only if it is at the end of the line."""
|
||||||
# a newline token ends a single physical line.
|
# a newline token ends a single physical line.
|
||||||
if processor.is_eol_token(token):
|
if processor.is_eol_token(token):
|
||||||
|
|
@ -638,13 +635,14 @@ class FileChecker(object):
|
||||||
self.run_physical_checks(line + "\n")
|
self.run_physical_checks(line + "\n")
|
||||||
|
|
||||||
|
|
||||||
def _pool_init(): # type: () -> None
|
def _pool_init() -> None:
|
||||||
"""Ensure correct signaling of ^C using multiprocessing.Pool."""
|
"""Ensure correct signaling of ^C using multiprocessing.Pool."""
|
||||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
|
|
||||||
|
|
||||||
def _try_initialize_processpool(job_count):
|
def _try_initialize_processpool(
|
||||||
# type: (int) -> Optional[multiprocessing.pool.Pool]
|
job_count: int,
|
||||||
|
) -> Optional[multiprocessing.pool.Pool]:
|
||||||
"""Return a new process pool instance if we are able to create one."""
|
"""Return a new process pool instance if we are able to create one."""
|
||||||
try:
|
try:
|
||||||
return multiprocessing.Pool(job_count, _pool_init)
|
return multiprocessing.Pool(job_count, _pool_init)
|
||||||
|
|
@ -673,8 +671,9 @@ def _run_checks(checker):
|
||||||
return checker.run_checks()
|
return checker.run_checks()
|
||||||
|
|
||||||
|
|
||||||
def find_offset(offset, mapping):
|
def find_offset(
|
||||||
# type: (int, processor._LogicalMapping) -> Tuple[int, int]
|
offset: int, mapping: processor._LogicalMapping
|
||||||
|
) -> Tuple[int, int]:
|
||||||
"""Find the offset tuple for a single offset."""
|
"""Find the offset tuple for a single offset."""
|
||||||
if isinstance(offset, tuple):
|
if isinstance(offset, tuple):
|
||||||
return offset
|
return offset
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,13 @@ class FailedToLoadPlugin(Flake8Exception):
|
||||||
|
|
||||||
FORMAT = 'Flake8 failed to load plugin "%(name)s" due to %(exc)s.'
|
FORMAT = 'Flake8 failed to load plugin "%(name)s" due to %(exc)s.'
|
||||||
|
|
||||||
def __init__(self, plugin_name, exception):
|
def __init__(self, plugin_name: str, exception: Exception) -> None:
|
||||||
# type: (str, Exception) -> None
|
|
||||||
"""Initialize our FailedToLoadPlugin exception."""
|
"""Initialize our FailedToLoadPlugin exception."""
|
||||||
self.plugin_name = plugin_name
|
self.plugin_name = plugin_name
|
||||||
self.original_exception = exception
|
self.original_exception = exception
|
||||||
super(FailedToLoadPlugin, self).__init__(plugin_name, exception)
|
super().__init__(plugin_name, exception)
|
||||||
|
|
||||||
def __str__(self): # type: () -> str
|
def __str__(self) -> str:
|
||||||
"""Format our exception message."""
|
"""Format our exception message."""
|
||||||
return self.FORMAT % {
|
return self.FORMAT % {
|
||||||
"name": self.plugin_name,
|
"name": self.plugin_name,
|
||||||
|
|
@ -37,18 +36,18 @@ class FailedToLoadPlugin(Flake8Exception):
|
||||||
class InvalidSyntax(Flake8Exception):
|
class InvalidSyntax(Flake8Exception):
|
||||||
"""Exception raised when tokenizing a file fails."""
|
"""Exception raised when tokenizing a file fails."""
|
||||||
|
|
||||||
def __init__(self, exception): # type: (Exception) -> None
|
def __init__(self, exception: Exception) -> None:
|
||||||
"""Initialize our InvalidSyntax exception."""
|
"""Initialize our InvalidSyntax exception."""
|
||||||
self.original_exception = exception
|
self.original_exception = exception
|
||||||
self.error_message = "{0}: {1}".format(
|
self.error_message = (
|
||||||
exception.__class__.__name__, exception.args[0]
|
f"{type(exception).__name__}: {exception.args[0]}"
|
||||||
)
|
)
|
||||||
self.error_code = "E902"
|
self.error_code = "E902"
|
||||||
self.line_number = 1
|
self.line_number = 1
|
||||||
self.column_number = 0
|
self.column_number = 0
|
||||||
super(InvalidSyntax, self).__init__(exception)
|
super().__init__(exception)
|
||||||
|
|
||||||
def __str__(self): # type: () -> str
|
def __str__(self) -> str:
|
||||||
"""Format our exception message."""
|
"""Format our exception message."""
|
||||||
return self.error_message
|
return self.error_message
|
||||||
|
|
||||||
|
|
@ -58,16 +57,13 @@ class PluginRequestedUnknownParameters(Flake8Exception):
|
||||||
|
|
||||||
FORMAT = '"%(name)s" requested unknown parameters causing %(exc)s'
|
FORMAT = '"%(name)s" requested unknown parameters causing %(exc)s'
|
||||||
|
|
||||||
def __init__(self, plugin, exception):
|
def __init__(self, plugin: Dict[str, str], exception: Exception) -> None:
|
||||||
# type: (Dict[str, str], Exception) -> None
|
|
||||||
"""Pop certain keyword arguments for initialization."""
|
"""Pop certain keyword arguments for initialization."""
|
||||||
self.plugin = plugin
|
self.plugin = plugin
|
||||||
self.original_exception = exception
|
self.original_exception = exception
|
||||||
super(PluginRequestedUnknownParameters, self).__init__(
|
super().__init__(plugin, exception)
|
||||||
plugin, exception
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self): # type: () -> str
|
def __str__(self) -> str:
|
||||||
"""Format our exception message."""
|
"""Format our exception message."""
|
||||||
return self.FORMAT % {
|
return self.FORMAT % {
|
||||||
"name": self.plugin["plugin_name"],
|
"name": self.plugin["plugin_name"],
|
||||||
|
|
@ -80,14 +76,13 @@ class PluginExecutionFailed(Flake8Exception):
|
||||||
|
|
||||||
FORMAT = '"%(name)s" failed during execution due to "%(exc)s"'
|
FORMAT = '"%(name)s" failed during execution due to "%(exc)s"'
|
||||||
|
|
||||||
def __init__(self, plugin, exception):
|
def __init__(self, plugin: Dict[str, str], exception: Exception) -> None:
|
||||||
# type: (Dict[str, str], Exception) -> None
|
|
||||||
"""Utilize keyword arguments for message generation."""
|
"""Utilize keyword arguments for message generation."""
|
||||||
self.plugin = plugin
|
self.plugin = plugin
|
||||||
self.original_exception = exception
|
self.original_exception = exception
|
||||||
super(PluginExecutionFailed, self).__init__(plugin, exception)
|
super().__init__(plugin, exception)
|
||||||
|
|
||||||
def __str__(self): # type: () -> str
|
def __str__(self) -> str:
|
||||||
"""Format our exception message."""
|
"""Format our exception message."""
|
||||||
return self.FORMAT % {
|
return self.FORMAT % {
|
||||||
"name": self.plugin["plugin_name"],
|
"name": self.plugin["plugin_name"],
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
"""The base class and interface for all formatting plugins."""
|
"""The base class and interface for all formatting plugins."""
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from typing import IO, List, Optional, Tuple
|
from typing import IO
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
if TYPE_CHECKING:
|
||||||
from flake8.statistics import Statistics
|
from flake8.statistics import Statistics
|
||||||
from flake8.style_guide import Violation
|
from flake8.style_guide import Violation
|
||||||
|
|
||||||
|
|
||||||
class BaseFormatter(object):
|
class BaseFormatter:
|
||||||
"""Class defining the formatter interface.
|
"""Class defining the formatter interface.
|
||||||
|
|
||||||
.. attribute:: options
|
.. attribute:: options
|
||||||
|
|
@ -31,8 +33,7 @@ class BaseFormatter(object):
|
||||||
output filename has been specified.
|
output filename has been specified.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, options):
|
def __init__(self, options: argparse.Namespace) -> None:
|
||||||
# type: (argparse.Namespace) -> None
|
|
||||||
"""Initialize with the options parsed from config and cli.
|
"""Initialize with the options parsed from config and cli.
|
||||||
|
|
||||||
This also calls a hook, :meth:`after_init`, so subclasses do not need
|
This also calls a hook, :meth:`after_init`, so subclasses do not need
|
||||||
|
|
@ -46,14 +47,14 @@ class BaseFormatter(object):
|
||||||
"""
|
"""
|
||||||
self.options = options
|
self.options = options
|
||||||
self.filename = options.output_file
|
self.filename = options.output_file
|
||||||
self.output_fd = None # type: Optional[IO[str]]
|
self.output_fd: Optional[IO[str]] = None
|
||||||
self.newline = "\n"
|
self.newline = "\n"
|
||||||
self.after_init()
|
self.after_init()
|
||||||
|
|
||||||
def after_init(self): # type: () -> None
|
def after_init(self) -> None:
|
||||||
"""Initialize the formatter further."""
|
"""Initialize the formatter further."""
|
||||||
|
|
||||||
def beginning(self, filename): # type: (str) -> None
|
def beginning(self, filename: str) -> None:
|
||||||
"""Notify the formatter that we're starting to process a file.
|
"""Notify the formatter that we're starting to process a file.
|
||||||
|
|
||||||
:param str filename:
|
:param str filename:
|
||||||
|
|
@ -61,7 +62,7 @@ class BaseFormatter(object):
|
||||||
from.
|
from.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def finished(self, filename): # type: (str) -> None
|
def finished(self, filename: str) -> None:
|
||||||
"""Notify the formatter that we've finished processing a file.
|
"""Notify the formatter that we've finished processing a file.
|
||||||
|
|
||||||
:param str filename:
|
:param str filename:
|
||||||
|
|
@ -69,7 +70,7 @@ class BaseFormatter(object):
|
||||||
from.
|
from.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def start(self): # type: () -> None
|
def start(self) -> None:
|
||||||
"""Prepare the formatter to receive input.
|
"""Prepare the formatter to receive input.
|
||||||
|
|
||||||
This defaults to initializing :attr:`output_fd` if :attr:`filename`
|
This defaults to initializing :attr:`output_fd` if :attr:`filename`
|
||||||
|
|
@ -77,7 +78,7 @@ class BaseFormatter(object):
|
||||||
if self.filename:
|
if self.filename:
|
||||||
self.output_fd = open(self.filename, "a")
|
self.output_fd = open(self.filename, "a")
|
||||||
|
|
||||||
def handle(self, error): # type: (Violation) -> None
|
def handle(self, error: "Violation") -> None:
|
||||||
"""Handle an error reported by Flake8.
|
"""Handle an error reported by Flake8.
|
||||||
|
|
||||||
This defaults to calling :meth:`format`, :meth:`show_source`, and
|
This defaults to calling :meth:`format`, :meth:`show_source`, and
|
||||||
|
|
@ -94,7 +95,7 @@ class BaseFormatter(object):
|
||||||
source = self.show_source(error)
|
source = self.show_source(error)
|
||||||
self.write(line, source)
|
self.write(line, source)
|
||||||
|
|
||||||
def format(self, error): # type: (Violation) -> Optional[str]
|
def format(self, error: "Violation") -> Optional[str]:
|
||||||
"""Format an error reported by Flake8.
|
"""Format an error reported by Flake8.
|
||||||
|
|
||||||
This method **must** be implemented by subclasses.
|
This method **must** be implemented by subclasses.
|
||||||
|
|
@ -113,23 +114,16 @@ class BaseFormatter(object):
|
||||||
"Subclass of BaseFormatter did not implement" " format."
|
"Subclass of BaseFormatter did not implement" " format."
|
||||||
)
|
)
|
||||||
|
|
||||||
def show_statistics(self, statistics): # type: (Statistics) -> None
|
def show_statistics(self, statistics: "Statistics") -> None:
|
||||||
"""Format and print the statistics."""
|
"""Format and print the statistics."""
|
||||||
for error_code in statistics.error_codes():
|
for error_code in statistics.error_codes():
|
||||||
stats_for_error_code = statistics.statistics_for(error_code)
|
stats_for_error_code = statistics.statistics_for(error_code)
|
||||||
statistic = next(stats_for_error_code)
|
statistic = next(stats_for_error_code)
|
||||||
count = statistic.count
|
count = statistic.count
|
||||||
count += sum(stat.count for stat in stats_for_error_code)
|
count += sum(stat.count for stat in stats_for_error_code)
|
||||||
self._write(
|
self._write(f"{count:<5} {error_code} {statistic.message}")
|
||||||
"{count:<5} {error_code} {message}".format(
|
|
||||||
count=count,
|
|
||||||
error_code=error_code,
|
|
||||||
message=statistic.message,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def show_benchmarks(self, benchmarks):
|
def show_benchmarks(self, benchmarks: List[Tuple[str, float]]) -> None:
|
||||||
# type: (List[Tuple[str, float]]) -> None
|
|
||||||
"""Format and print the benchmarks."""
|
"""Format and print the benchmarks."""
|
||||||
# NOTE(sigmavirus24): The format strings are a little confusing, even
|
# NOTE(sigmavirus24): The format strings are a little confusing, even
|
||||||
# to me, so here's a quick explanation:
|
# to me, so here's a quick explanation:
|
||||||
|
|
@ -150,7 +144,7 @@ class BaseFormatter(object):
|
||||||
benchmark = float_format(statistic=statistic, value=value)
|
benchmark = float_format(statistic=statistic, value=value)
|
||||||
self._write(benchmark)
|
self._write(benchmark)
|
||||||
|
|
||||||
def show_source(self, error): # type: (Violation) -> Optional[str]
|
def show_source(self, error: "Violation") -> Optional[str]:
|
||||||
"""Show the physical line generating the error.
|
"""Show the physical line generating the error.
|
||||||
|
|
||||||
This also adds an indicator for the particular part of the line that
|
This also adds an indicator for the particular part of the line that
|
||||||
|
|
@ -179,17 +173,16 @@ class BaseFormatter(object):
|
||||||
)
|
)
|
||||||
# Physical lines have a newline at the end, no need to add an extra
|
# Physical lines have a newline at the end, no need to add an extra
|
||||||
# one
|
# one
|
||||||
return "{}{}^".format(error.physical_line, indent)
|
return f"{error.physical_line}{indent}^"
|
||||||
|
|
||||||
def _write(self, output): # type: (str) -> None
|
def _write(self, output: str) -> None:
|
||||||
"""Handle logic of whether to use an output file or print()."""
|
"""Handle logic of whether to use an output file or print()."""
|
||||||
if self.output_fd is not None:
|
if self.output_fd is not None:
|
||||||
self.output_fd.write(output + self.newline)
|
self.output_fd.write(output + self.newline)
|
||||||
if self.output_fd is None or self.options.tee:
|
if self.output_fd is None or self.options.tee:
|
||||||
print(output, end=self.newline)
|
print(output, end=self.newline)
|
||||||
|
|
||||||
def write(self, line, source):
|
def write(self, line: Optional[str], source: Optional[str]) -> None:
|
||||||
# type: (Optional[str], Optional[str]) -> None
|
|
||||||
"""Write the line either to the output file or stdout.
|
"""Write the line either to the output file or stdout.
|
||||||
|
|
||||||
This handles deciding whether to write to a file or print to standard
|
This handles deciding whether to write to a file or print to standard
|
||||||
|
|
@ -207,7 +200,7 @@ class BaseFormatter(object):
|
||||||
if source:
|
if source:
|
||||||
self._write(source)
|
self._write(source)
|
||||||
|
|
||||||
def stop(self): # type: () -> None
|
def stop(self) -> None:
|
||||||
"""Clean up after reporting is finished."""
|
"""Clean up after reporting is finished."""
|
||||||
if self.output_fd is not None:
|
if self.output_fd is not None:
|
||||||
self.output_fd.close()
|
self.output_fd.close()
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
"""Default formatting class for Flake8."""
|
"""Default formatting class for Flake8."""
|
||||||
from typing import Optional, Set
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from flake8.formatting import base
|
from flake8.formatting import base
|
||||||
|
|
||||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
if TYPE_CHECKING:
|
||||||
from flake8.style_guide import Violation
|
from flake8.style_guide import Violation
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -23,9 +25,9 @@ class SimpleFormatter(base.BaseFormatter):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
error_format = None # type: str
|
error_format: str
|
||||||
|
|
||||||
def format(self, error): # type: (Violation) -> Optional[str]
|
def format(self, error: "Violation") -> Optional[str]:
|
||||||
"""Format and write error out.
|
"""Format and write error out.
|
||||||
|
|
||||||
If an output filename is specified, write formatted errors to that
|
If an output filename is specified, write formatted errors to that
|
||||||
|
|
@ -49,7 +51,7 @@ class Default(SimpleFormatter):
|
||||||
|
|
||||||
error_format = "%(path)s:%(row)d:%(col)d: %(code)s %(text)s"
|
error_format = "%(path)s:%(row)d:%(col)d: %(code)s %(text)s"
|
||||||
|
|
||||||
def after_init(self): # type: () -> None
|
def after_init(self) -> None:
|
||||||
"""Check for a custom format string."""
|
"""Check for a custom format string."""
|
||||||
if self.options.format.lower() != "default":
|
if self.options.format.lower() != "default":
|
||||||
self.error_format = self.options.format
|
self.error_format = self.options.format
|
||||||
|
|
@ -66,18 +68,18 @@ class FilenameOnly(SimpleFormatter):
|
||||||
|
|
||||||
error_format = "%(path)s"
|
error_format = "%(path)s"
|
||||||
|
|
||||||
def after_init(self): # type: () -> None
|
def after_init(self) -> None:
|
||||||
"""Initialize our set of filenames."""
|
"""Initialize our set of filenames."""
|
||||||
self.filenames_already_printed = set() # type: Set[str]
|
self.filenames_already_printed: Set[str] = set()
|
||||||
|
|
||||||
def show_source(self, error): # type: (Violation) -> Optional[str]
|
def show_source(self, error: "Violation") -> Optional[str]:
|
||||||
"""Do not include the source code."""
|
"""Do not include the source code."""
|
||||||
|
|
||||||
def format(self, error): # type: (Violation) -> Optional[str]
|
def format(self, error: "Violation") -> Optional[str]:
|
||||||
"""Ensure we only print each error once."""
|
"""Ensure we only print each error once."""
|
||||||
if error.filename not in self.filenames_already_printed:
|
if error.filename not in self.filenames_already_printed:
|
||||||
self.filenames_already_printed.add(error.filename)
|
self.filenames_already_printed.add(error.filename)
|
||||||
return super(FilenameOnly, self).format(error)
|
return super().format(error)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -85,8 +87,8 @@ class FilenameOnly(SimpleFormatter):
|
||||||
class Nothing(base.BaseFormatter):
|
class Nothing(base.BaseFormatter):
|
||||||
"""Print absolutely nothing."""
|
"""Print absolutely nothing."""
|
||||||
|
|
||||||
def format(self, error): # type: (Violation) -> Optional[str]
|
def format(self, error: "Violation") -> Optional[str]:
|
||||||
"""Do nothing."""
|
"""Do nothing."""
|
||||||
|
|
||||||
def show_source(self, error): # type: (Violation) -> Optional[str]
|
def show_source(self, error: "Violation") -> Optional[str]:
|
||||||
"""Do not print the source."""
|
"""Do not print the source."""
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
"""Module containing the application logic for Flake8."""
|
"""Module containing the application logic for Flake8."""
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from typing import Dict, List, Optional, Set, Tuple
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import Type
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import flake8
|
import flake8
|
||||||
from flake8 import checker
|
from flake8 import checker
|
||||||
|
|
@ -14,19 +18,19 @@ from flake8 import exceptions
|
||||||
from flake8 import style_guide
|
from flake8 import style_guide
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
from flake8.main import options
|
from flake8.main import options
|
||||||
from flake8.options import aggregator, config
|
from flake8.options import aggregator
|
||||||
|
from flake8.options import config
|
||||||
from flake8.options import manager
|
from flake8.options import manager
|
||||||
from flake8.plugins import manager as plugin_manager
|
from flake8.plugins import manager as plugin_manager
|
||||||
|
|
||||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
if TYPE_CHECKING:
|
||||||
from typing import Type # `typing.Type` was introduced in 3.5.2
|
|
||||||
from flake8.formatting.base import BaseFormatter
|
from flake8.formatting.base import BaseFormatter
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Application(object):
|
class Application:
|
||||||
"""Abstract our application into a class."""
|
"""Abstract our application into a class."""
|
||||||
|
|
||||||
def __init__(self, program="flake8", version=flake8.__version__):
|
def __init__(self, program="flake8", version=flake8.__version__):
|
||||||
|
|
@ -40,7 +44,7 @@ class Application(object):
|
||||||
#: The timestamp when the Application instance was instantiated.
|
#: The timestamp when the Application instance was instantiated.
|
||||||
self.start_time = time.time()
|
self.start_time = time.time()
|
||||||
#: The timestamp when the Application finished reported errors.
|
#: The timestamp when the Application finished reported errors.
|
||||||
self.end_time = None # type: float
|
self.end_time: float = None
|
||||||
#: The name of the program being run
|
#: The name of the program being run
|
||||||
self.program = program
|
self.program = program
|
||||||
#: The version of the program being run
|
#: The version of the program being run
|
||||||
|
|
@ -59,26 +63,24 @@ class Application(object):
|
||||||
options.register_default_options(self.option_manager)
|
options.register_default_options(self.option_manager)
|
||||||
|
|
||||||
#: The instance of :class:`flake8.plugins.manager.Checkers`
|
#: The instance of :class:`flake8.plugins.manager.Checkers`
|
||||||
self.check_plugins = None # type: plugin_manager.Checkers
|
self.check_plugins: plugin_manager.Checkers = None
|
||||||
# fmt: off
|
|
||||||
#: The instance of :class:`flake8.plugins.manager.ReportFormatters`
|
#: The instance of :class:`flake8.plugins.manager.ReportFormatters`
|
||||||
self.formatting_plugins = None # type: plugin_manager.ReportFormatters
|
self.formatting_plugins: plugin_manager.ReportFormatters = None
|
||||||
# fmt: on
|
|
||||||
#: The user-selected formatter from :attr:`formatting_plugins`
|
#: The user-selected formatter from :attr:`formatting_plugins`
|
||||||
self.formatter = None # type: BaseFormatter
|
self.formatter: BaseFormatter = None
|
||||||
#: The :class:`flake8.style_guide.StyleGuideManager` built from the
|
#: The :class:`flake8.style_guide.StyleGuideManager` built from the
|
||||||
#: user's options
|
#: user's options
|
||||||
self.guide = None # type: style_guide.StyleGuideManager
|
self.guide: style_guide.StyleGuideManager = None
|
||||||
#: The :class:`flake8.checker.Manager` that will handle running all of
|
#: The :class:`flake8.checker.Manager` that will handle running all of
|
||||||
#: the checks selected by the user.
|
#: the checks selected by the user.
|
||||||
self.file_checker_manager = None # type: checker.Manager
|
self.file_checker_manager: checker.Manager = None
|
||||||
|
|
||||||
#: The user-supplied options parsed into an instance of
|
#: The user-supplied options parsed into an instance of
|
||||||
#: :class:`argparse.Namespace`
|
#: :class:`argparse.Namespace`
|
||||||
self.options = None # type: argparse.Namespace
|
self.options: argparse.Namespace = None
|
||||||
#: The left over arguments that were not parsed by
|
#: The left over arguments that were not parsed by
|
||||||
#: :attr:`option_manager`
|
#: :attr:`option_manager`
|
||||||
self.args = None # type: List[str]
|
self.args: List[str] = None
|
||||||
#: The number of errors, warnings, and other messages after running
|
#: The number of errors, warnings, and other messages after running
|
||||||
#: flake8 and taking into account ignored errors and lines.
|
#: flake8 and taking into account ignored errors and lines.
|
||||||
self.result_count = 0
|
self.result_count = 0
|
||||||
|
|
@ -92,10 +94,11 @@ class Application(object):
|
||||||
#: Whether the program is processing a diff or not
|
#: Whether the program is processing a diff or not
|
||||||
self.running_against_diff = False
|
self.running_against_diff = False
|
||||||
#: The parsed diff information
|
#: The parsed diff information
|
||||||
self.parsed_diff = {} # type: Dict[str, Set[int]]
|
self.parsed_diff: Dict[str, Set[int]] = {}
|
||||||
|
|
||||||
def parse_preliminary_options(self, argv):
|
def parse_preliminary_options(
|
||||||
# type: (List[str]) -> Tuple[argparse.Namespace, List[str]]
|
self, argv: List[str]
|
||||||
|
) -> Tuple[argparse.Namespace, List[str]]:
|
||||||
"""Get preliminary options from the CLI, pre-plugin-loading.
|
"""Get preliminary options from the CLI, pre-plugin-loading.
|
||||||
|
|
||||||
We need to know the values of a few standard options so that we can
|
We need to know the values of a few standard options so that we can
|
||||||
|
|
@ -119,8 +122,7 @@ class Application(object):
|
||||||
rest.extend(("--output-file", args.output_file))
|
rest.extend(("--output-file", args.output_file))
|
||||||
return args, rest
|
return args, rest
|
||||||
|
|
||||||
def exit(self):
|
def exit(self) -> None:
|
||||||
# type: () -> None
|
|
||||||
"""Handle finalization and exiting the program.
|
"""Handle finalization and exiting the program.
|
||||||
|
|
||||||
This should be the last thing called on the application instance. It
|
This should be the last thing called on the application instance. It
|
||||||
|
|
@ -136,8 +138,7 @@ class Application(object):
|
||||||
(self.result_count > 0) or self.catastrophic_failure
|
(self.result_count > 0) or self.catastrophic_failure
|
||||||
)
|
)
|
||||||
|
|
||||||
def find_plugins(self, config_finder):
|
def find_plugins(self, config_finder: config.ConfigFileFinder) -> None:
|
||||||
# type: (config.ConfigFileFinder) -> None
|
|
||||||
"""Find and load the plugins for this application.
|
"""Find and load the plugins for this application.
|
||||||
|
|
||||||
Set the :attr:`check_plugins` and :attr:`formatting_plugins` attributes
|
Set the :attr:`check_plugins` and :attr:`formatting_plugins` attributes
|
||||||
|
|
@ -159,8 +160,7 @@ class Application(object):
|
||||||
self.check_plugins.load_plugins()
|
self.check_plugins.load_plugins()
|
||||||
self.formatting_plugins.load_plugins()
|
self.formatting_plugins.load_plugins()
|
||||||
|
|
||||||
def register_plugin_options(self):
|
def register_plugin_options(self) -> None:
|
||||||
# type: () -> None
|
|
||||||
"""Register options provided by plugins to our option manager."""
|
"""Register options provided by plugins to our option manager."""
|
||||||
self.check_plugins.register_options(self.option_manager)
|
self.check_plugins.register_options(self.option_manager)
|
||||||
self.check_plugins.register_plugin_versions(self.option_manager)
|
self.check_plugins.register_plugin_versions(self.option_manager)
|
||||||
|
|
@ -168,10 +168,9 @@ class Application(object):
|
||||||
|
|
||||||
def parse_configuration_and_cli(
|
def parse_configuration_and_cli(
|
||||||
self,
|
self,
|
||||||
config_finder, # type: config.ConfigFileFinder
|
config_finder: config.ConfigFileFinder,
|
||||||
argv, # type: List[str]
|
argv: List[str],
|
||||||
):
|
) -> None:
|
||||||
# type: (...) -> None
|
|
||||||
"""Parse configuration files and the CLI options.
|
"""Parse configuration files and the CLI options.
|
||||||
|
|
||||||
:param config.ConfigFileFinder config_finder:
|
:param config.ConfigFileFinder config_finder:
|
||||||
|
|
@ -211,8 +210,9 @@ class Application(object):
|
||||||
|
|
||||||
return formatter_plugin.execute
|
return formatter_plugin.execute
|
||||||
|
|
||||||
def make_formatter(self, formatter_class=None):
|
def make_formatter(
|
||||||
# type: (Optional[Type[BaseFormatter]]) -> None
|
self, formatter_class: Optional[Type["BaseFormatter"]] = None
|
||||||
|
) -> None:
|
||||||
"""Initialize a formatter based on the parsed options."""
|
"""Initialize a formatter based on the parsed options."""
|
||||||
format_plugin = self.options.format
|
format_plugin = self.options.format
|
||||||
if 1 <= self.options.quiet < 2:
|
if 1 <= self.options.quiet < 2:
|
||||||
|
|
@ -225,8 +225,7 @@ class Application(object):
|
||||||
|
|
||||||
self.formatter = formatter_class(self.options)
|
self.formatter = formatter_class(self.options)
|
||||||
|
|
||||||
def make_guide(self):
|
def make_guide(self) -> None:
|
||||||
# type: () -> None
|
|
||||||
"""Initialize our StyleGuide."""
|
"""Initialize our StyleGuide."""
|
||||||
self.guide = style_guide.StyleGuideManager(
|
self.guide = style_guide.StyleGuideManager(
|
||||||
self.options, self.formatter
|
self.options, self.formatter
|
||||||
|
|
@ -235,8 +234,7 @@ class Application(object):
|
||||||
if self.running_against_diff:
|
if self.running_against_diff:
|
||||||
self.guide.add_diff_ranges(self.parsed_diff)
|
self.guide.add_diff_ranges(self.parsed_diff)
|
||||||
|
|
||||||
def make_file_checker_manager(self):
|
def make_file_checker_manager(self) -> None:
|
||||||
# type: () -> None
|
|
||||||
"""Initialize our FileChecker Manager."""
|
"""Initialize our FileChecker Manager."""
|
||||||
self.file_checker_manager = checker.Manager(
|
self.file_checker_manager = checker.Manager(
|
||||||
style_guide=self.guide,
|
style_guide=self.guide,
|
||||||
|
|
@ -244,8 +242,7 @@ class Application(object):
|
||||||
checker_plugins=self.check_plugins,
|
checker_plugins=self.check_plugins,
|
||||||
)
|
)
|
||||||
|
|
||||||
def run_checks(self, files=None):
|
def run_checks(self, files: Optional[List[str]] = None) -> None:
|
||||||
# type: (Optional[List[str]]) -> None
|
|
||||||
"""Run the actual checks with the FileChecker Manager.
|
"""Run the actual checks with the FileChecker Manager.
|
||||||
|
|
||||||
This method encapsulates the logic to make a
|
This method encapsulates the logic to make a
|
||||||
|
|
@ -278,15 +275,14 @@ class Application(object):
|
||||||
add_statistic = statistics.append
|
add_statistic = statistics.append
|
||||||
for statistic in defaults.STATISTIC_NAMES + ("files",):
|
for statistic in defaults.STATISTIC_NAMES + ("files",):
|
||||||
value = self.file_checker_manager.statistics[statistic]
|
value = self.file_checker_manager.statistics[statistic]
|
||||||
total_description = "total " + statistic + " processed"
|
total_description = f"total {statistic} processed"
|
||||||
add_statistic((total_description, value))
|
add_statistic((total_description, value))
|
||||||
per_second_description = statistic + " processed per second"
|
per_second_description = f"{statistic} processed per second"
|
||||||
add_statistic((per_second_description, int(value / time_elapsed)))
|
add_statistic((per_second_description, int(value / time_elapsed)))
|
||||||
|
|
||||||
self.formatter.show_benchmarks(statistics)
|
self.formatter.show_benchmarks(statistics)
|
||||||
|
|
||||||
def report_errors(self):
|
def report_errors(self) -> None:
|
||||||
# type: () -> None
|
|
||||||
"""Report all the errors found by flake8 3.0.
|
"""Report all the errors found by flake8 3.0.
|
||||||
|
|
||||||
This also updates the :attr:`result_count` attribute with the total
|
This also updates the :attr:`result_count` attribute with the total
|
||||||
|
|
@ -308,8 +304,7 @@ class Application(object):
|
||||||
|
|
||||||
self.formatter.show_statistics(self.guide.stats)
|
self.formatter.show_statistics(self.guide.stats)
|
||||||
|
|
||||||
def initialize(self, argv):
|
def initialize(self, argv: List[str]) -> None:
|
||||||
# type: (List[str]) -> None
|
|
||||||
"""Initialize the application to be run.
|
"""Initialize the application to be run.
|
||||||
|
|
||||||
This finds the plugins, registers their options, and parses the
|
This finds the plugins, registers their options, and parses the
|
||||||
|
|
@ -343,14 +338,12 @@ class Application(object):
|
||||||
self.report_benchmarks()
|
self.report_benchmarks()
|
||||||
self.formatter.stop()
|
self.formatter.stop()
|
||||||
|
|
||||||
def _run(self, argv):
|
def _run(self, argv: List[str]) -> None:
|
||||||
# type: (List[str]) -> None
|
|
||||||
self.initialize(argv)
|
self.initialize(argv)
|
||||||
self.run_checks()
|
self.run_checks()
|
||||||
self.report()
|
self.report()
|
||||||
|
|
||||||
def run(self, argv):
|
def run(self, argv: List[str]) -> None:
|
||||||
# type: (List[str]) -> None
|
|
||||||
"""Run our application.
|
"""Run our application.
|
||||||
|
|
||||||
This method will also handle KeyboardInterrupt exceptions for the
|
This method will also handle KeyboardInterrupt exceptions for the
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
"""Command-line implementation of flake8."""
|
"""Command-line implementation of flake8."""
|
||||||
import sys
|
import sys
|
||||||
from typing import List, Optional
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from flake8.main import application
|
from flake8.main import application
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None):
|
def main(argv: Optional[List[str]] = None) -> None:
|
||||||
# type: (Optional[List[str]]) -> None
|
|
||||||
"""Execute the main bit of the application.
|
"""Execute the main bit of the application.
|
||||||
|
|
||||||
This handles the creation of an instance of :class:`Application`, runs it,
|
This handles the creation of an instance of :class:`Application`, runs it,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
"""Module containing the logic for our debugging logic."""
|
"""Module containing the logic for our debugging logic."""
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
import platform
|
import platform
|
||||||
from typing import Dict, List
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
class DebugAction(argparse.Action):
|
class DebugAction(argparse.Action):
|
||||||
|
|
@ -17,7 +16,7 @@ class DebugAction(argparse.Action):
|
||||||
used to delay response.
|
used to delay response.
|
||||||
"""
|
"""
|
||||||
self._option_manager = kwargs.pop("option_manager")
|
self._option_manager = kwargs.pop("option_manager")
|
||||||
super(DebugAction, self).__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
"""Perform the argparse action for printing debug information."""
|
"""Perform the argparse action for printing debug information."""
|
||||||
|
|
@ -60,6 +59,6 @@ def plugins_from(option_manager):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def dependencies(): # type: () -> List[Dict[str, str]]
|
def dependencies() -> List[Dict[str, str]]:
|
||||||
"""Generate the list of dependencies we care about."""
|
"""Generate the list of dependencies we care about."""
|
||||||
return []
|
return []
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@ from flake8 import defaults
|
||||||
from flake8.main import debug
|
from flake8.main import debug
|
||||||
|
|
||||||
|
|
||||||
def register_preliminary_options(parser):
|
def register_preliminary_options(parser: argparse.ArgumentParser) -> None:
|
||||||
# type: (argparse.ArgumentParser) -> None
|
|
||||||
"""Register the preliminary options on our OptionManager.
|
"""Register the preliminary options on our OptionManager.
|
||||||
|
|
||||||
The preliminary options include:
|
The preliminary options include:
|
||||||
|
|
@ -64,7 +63,7 @@ def register_preliminary_options(parser):
|
||||||
class JobsArgument:
|
class JobsArgument:
|
||||||
"""Type callback for the --jobs argument."""
|
"""Type callback for the --jobs argument."""
|
||||||
|
|
||||||
def __init__(self, arg): # type: (str) -> None
|
def __init__(self, arg: str) -> None:
|
||||||
"""Parse and validate the --jobs argument.
|
"""Parse and validate the --jobs argument.
|
||||||
|
|
||||||
:param str arg:
|
:param str arg:
|
||||||
|
|
@ -78,7 +77,7 @@ class JobsArgument:
|
||||||
self.n_jobs = int(arg)
|
self.n_jobs = int(arg)
|
||||||
else:
|
else:
|
||||||
raise argparse.ArgumentTypeError(
|
raise argparse.ArgumentTypeError(
|
||||||
"{!r} must be 'auto' or an integer.".format(arg),
|
f"{arg!r} must be 'auto' or an integer.",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@ applies the user-specified command-line configuration on top of it.
|
||||||
"""
|
"""
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
from typing import List, Tuple
|
from typing import List
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from flake8.options import config
|
from flake8.options import config
|
||||||
from flake8.options.manager import OptionManager
|
from flake8.options.manager import OptionManager
|
||||||
|
|
@ -14,10 +15,10 @@ LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def aggregate_options(
|
def aggregate_options(
|
||||||
manager, # type: OptionManager
|
manager: OptionManager,
|
||||||
config_finder, # type: config.ConfigFileFinder
|
config_finder: config.ConfigFileFinder,
|
||||||
argv, # type: List[str]
|
argv: List[str],
|
||||||
): # type: (...) -> Tuple[argparse.Namespace, List[str]]
|
) -> Tuple[argparse.Namespace, List[str]]:
|
||||||
"""Aggregate and merge CLI and config file options.
|
"""Aggregate and merge CLI and config file options.
|
||||||
|
|
||||||
:param flake8.options.manager.OptionManager manager:
|
:param flake8.options.manager.OptionManager manager:
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ import collections
|
||||||
import configparser
|
import configparser
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
from typing import List, Optional, Tuple
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
|
|
||||||
|
|
@ -12,17 +14,16 @@ LOG = logging.getLogger(__name__)
|
||||||
__all__ = ("ConfigFileFinder", "MergedConfigParser")
|
__all__ = ("ConfigFileFinder", "MergedConfigParser")
|
||||||
|
|
||||||
|
|
||||||
class ConfigFileFinder(object):
|
class ConfigFileFinder:
|
||||||
"""Encapsulate the logic for finding and reading config files."""
|
"""Encapsulate the logic for finding and reading config files."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
program_name,
|
program_name: str,
|
||||||
extra_config_files=None,
|
extra_config_files: Optional[List[str]] = None,
|
||||||
config_file=None,
|
config_file: Optional[str] = None,
|
||||||
ignore_config_files=False,
|
ignore_config_files: bool = False,
|
||||||
):
|
) -> None:
|
||||||
# type: (str, Optional[List[str]], Optional[str], bool) -> None
|
|
||||||
"""Initialize object to find config files.
|
"""Initialize object to find config files.
|
||||||
|
|
||||||
:param str program_name:
|
:param str program_name:
|
||||||
|
|
@ -50,16 +51,15 @@ class ConfigFileFinder(object):
|
||||||
self.user_config_file = self._user_config_file(program_name)
|
self.user_config_file = self._user_config_file(program_name)
|
||||||
|
|
||||||
# List of filenames to find in the local/project directory
|
# List of filenames to find in the local/project directory
|
||||||
self.project_filenames = ("setup.cfg", "tox.ini", "." + program_name)
|
self.project_filenames = ("setup.cfg", "tox.ini", f".{program_name}")
|
||||||
|
|
||||||
self.local_directory = os.path.abspath(os.curdir)
|
self.local_directory = os.path.abspath(os.curdir)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _user_config_file(program_name):
|
def _user_config_file(program_name: str) -> str:
|
||||||
# type: (str) -> str
|
|
||||||
if utils.is_windows():
|
if utils.is_windows():
|
||||||
home_dir = os.path.expanduser("~")
|
home_dir = os.path.expanduser("~")
|
||||||
config_file_basename = "." + program_name
|
config_file_basename = f".{program_name}"
|
||||||
else:
|
else:
|
||||||
home_dir = os.environ.get(
|
home_dir = os.environ.get(
|
||||||
"XDG_CONFIG_HOME", os.path.expanduser("~/.config")
|
"XDG_CONFIG_HOME", os.path.expanduser("~/.config")
|
||||||
|
|
@ -69,8 +69,9 @@ class ConfigFileFinder(object):
|
||||||
return os.path.join(home_dir, config_file_basename)
|
return os.path.join(home_dir, config_file_basename)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _read_config(*files):
|
def _read_config(
|
||||||
# type: (*str) -> Tuple[configparser.RawConfigParser, List[str]]
|
*files: str,
|
||||||
|
) -> Tuple[configparser.RawConfigParser, List[str]]:
|
||||||
config = configparser.RawConfigParser()
|
config = configparser.RawConfigParser()
|
||||||
|
|
||||||
found_files = []
|
found_files = []
|
||||||
|
|
@ -91,8 +92,7 @@ class ConfigFileFinder(object):
|
||||||
)
|
)
|
||||||
return (config, found_files)
|
return (config, found_files)
|
||||||
|
|
||||||
def cli_config(self, files):
|
def cli_config(self, files: str) -> configparser.RawConfigParser:
|
||||||
# type: (str) -> configparser.RawConfigParser
|
|
||||||
"""Read and parse the config file specified on the command-line."""
|
"""Read and parse the config file specified on the command-line."""
|
||||||
config, found_files = self._read_config(files)
|
config, found_files = self._read_config(files)
|
||||||
if found_files:
|
if found_files:
|
||||||
|
|
@ -154,7 +154,7 @@ class ConfigFileFinder(object):
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
class MergedConfigParser(object):
|
class MergedConfigParser:
|
||||||
"""Encapsulate merging different types of configuration files.
|
"""Encapsulate merging different types of configuration files.
|
||||||
|
|
||||||
This parses out the options registered that were specified in the
|
This parses out the options registered that were specified in the
|
||||||
|
|
@ -344,7 +344,7 @@ def get_local_plugins(config_finder):
|
||||||
|
|
||||||
base_dirs = {os.path.dirname(cf) for cf in config_files}
|
base_dirs = {os.path.dirname(cf) for cf in config_files}
|
||||||
|
|
||||||
section = "%s:local-plugins" % config_finder.program_name
|
section = f"{config_finder.program_name}:local-plugins"
|
||||||
for plugin_type in ["extension", "report"]:
|
for plugin_type in ["extension", "report"]:
|
||||||
if config.has_option(section, plugin_type):
|
if config.has_option(section, plugin_type):
|
||||||
local_plugins_string = config.get(section, plugin_type).strip()
|
local_plugins_string = config.get(section, plugin_type).strip()
|
||||||
|
|
@ -358,7 +358,7 @@ def get_local_plugins(config_finder):
|
||||||
raw_paths = utils.parse_comma_separated_list(
|
raw_paths = utils.parse_comma_separated_list(
|
||||||
config.get(section, "paths").strip()
|
config.get(section, "paths").strip()
|
||||||
)
|
)
|
||||||
norm_paths = [] # type: List[str]
|
norm_paths: List[str] = []
|
||||||
for base_dir in base_dirs:
|
for base_dir in base_dirs:
|
||||||
norm_paths.extend(
|
norm_paths.extend(
|
||||||
path
|
path
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,25 @@ import contextlib
|
||||||
import enum
|
import enum
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Callable, cast, Dict, Generator, List, Mapping
|
from typing import Any
|
||||||
from typing import Optional, Sequence, Set, Tuple, Union
|
from typing import Callable
|
||||||
|
from typing import cast
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Generator
|
||||||
|
from typing import List
|
||||||
|
from typing import Mapping
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Sequence
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import Type
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
|
|
||||||
if False: # TYPE_CHECKING
|
if TYPE_CHECKING:
|
||||||
from typing import NoReturn
|
from typing import NoReturn
|
||||||
from typing import Type
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -21,7 +32,7 @@ LOG = logging.getLogger(__name__)
|
||||||
_ARG = enum.Enum("_ARG", "NO")
|
_ARG = enum.Enum("_ARG", "NO")
|
||||||
|
|
||||||
|
|
||||||
_optparse_callable_map = {
|
_optparse_callable_map: Dict[str, Union[Type[Any], _ARG]] = {
|
||||||
"int": int,
|
"int": int,
|
||||||
"long": int,
|
"long": int,
|
||||||
"string": str,
|
"string": str,
|
||||||
|
|
@ -30,27 +41,25 @@ _optparse_callable_map = {
|
||||||
"choice": _ARG.NO,
|
"choice": _ARG.NO,
|
||||||
# optparse allows this but does not document it
|
# optparse allows this but does not document it
|
||||||
"str": str,
|
"str": str,
|
||||||
} # type: Dict[str, Union[Type[Any], _ARG]]
|
}
|
||||||
|
|
||||||
|
|
||||||
class _CallbackAction(argparse.Action):
|
class _CallbackAction(argparse.Action):
|
||||||
"""Shim for optparse-style callback actions."""
|
"""Shim for optparse-style callback actions."""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
# type: (*Any, **Any) -> None
|
|
||||||
self._callback = kwargs.pop("callback")
|
self._callback = kwargs.pop("callback")
|
||||||
self._callback_args = kwargs.pop("callback_args", ())
|
self._callback_args = kwargs.pop("callback_args", ())
|
||||||
self._callback_kwargs = kwargs.pop("callback_kwargs", {})
|
self._callback_kwargs = kwargs.pop("callback_kwargs", {})
|
||||||
super(_CallbackAction, self).__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def __call__(
|
def __call__(
|
||||||
self,
|
self,
|
||||||
parser, # type: argparse.ArgumentParser
|
parser: argparse.ArgumentParser,
|
||||||
namespace, # type: argparse.Namespace
|
namespace: argparse.Namespace,
|
||||||
values, # type: Optional[Union[Sequence[str], str]]
|
values: Optional[Union[Sequence[str], str]],
|
||||||
option_string=None, # type: Optional[str]
|
option_string: Optional[str] = None,
|
||||||
):
|
) -> None:
|
||||||
# type: (...) -> None
|
|
||||||
if not values:
|
if not values:
|
||||||
values = None
|
values = None
|
||||||
elif isinstance(values, list) and len(values) > 1:
|
elif isinstance(values, list) and len(values) > 1:
|
||||||
|
|
@ -61,23 +70,24 @@ class _CallbackAction(argparse.Action):
|
||||||
values,
|
values,
|
||||||
parser,
|
parser,
|
||||||
*self._callback_args,
|
*self._callback_args,
|
||||||
**self._callback_kwargs
|
**self._callback_kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _flake8_normalize(value, *args, **kwargs):
|
def _flake8_normalize(
|
||||||
# type: (str, *str, **bool) -> Union[str, List[str]]
|
value: str, *args: str, **kwargs: bool
|
||||||
|
) -> Union[str, List[str]]:
|
||||||
comma_separated_list = kwargs.pop("comma_separated_list", False)
|
comma_separated_list = kwargs.pop("comma_separated_list", False)
|
||||||
normalize_paths = kwargs.pop("normalize_paths", False)
|
normalize_paths = kwargs.pop("normalize_paths", False)
|
||||||
if kwargs:
|
if kwargs:
|
||||||
raise TypeError("Unexpected keyword args: {}".format(kwargs))
|
raise TypeError(f"Unexpected keyword args: {kwargs}")
|
||||||
|
|
||||||
ret = value # type: Union[str, List[str]]
|
ret: Union[str, List[str]] = value
|
||||||
if comma_separated_list and isinstance(ret, utils.string_types):
|
if comma_separated_list and isinstance(ret, str):
|
||||||
ret = utils.parse_comma_separated_list(value)
|
ret = utils.parse_comma_separated_list(value)
|
||||||
|
|
||||||
if normalize_paths:
|
if normalize_paths:
|
||||||
if isinstance(ret, utils.string_types):
|
if isinstance(ret, str):
|
||||||
ret = utils.normalize_path(ret, *args)
|
ret = utils.normalize_path(ret, *args)
|
||||||
else:
|
else:
|
||||||
ret = utils.normalize_paths(ret, *args)
|
ret = utils.normalize_paths(ret, *args)
|
||||||
|
|
@ -85,34 +95,34 @@ def _flake8_normalize(value, *args, **kwargs):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class Option(object):
|
class Option:
|
||||||
"""Our wrapper around an argparse argument parsers to add features."""
|
"""Our wrapper around an argparse argument parsers to add features."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
short_option_name=_ARG.NO, # type: Union[str, _ARG]
|
short_option_name: Union[str, _ARG] = _ARG.NO,
|
||||||
long_option_name=_ARG.NO, # type: Union[str, _ARG]
|
long_option_name: Union[str, _ARG] = _ARG.NO,
|
||||||
# Options below here are taken from the optparse.Option class
|
# Options below here are taken from the optparse.Option class
|
||||||
action=_ARG.NO, # type: Union[str, Type[argparse.Action], _ARG]
|
action: Union[str, Type[argparse.Action], _ARG] = _ARG.NO,
|
||||||
default=_ARG.NO, # type: Union[Any, _ARG]
|
default: Union[Any, _ARG] = _ARG.NO,
|
||||||
type=_ARG.NO, # type: Union[str, Callable[..., Any], _ARG]
|
type: Union[str, Callable[..., Any], _ARG] = _ARG.NO,
|
||||||
dest=_ARG.NO, # type: Union[str, _ARG]
|
dest: Union[str, _ARG] = _ARG.NO,
|
||||||
nargs=_ARG.NO, # type: Union[int, str, _ARG]
|
nargs: Union[int, str, _ARG] = _ARG.NO,
|
||||||
const=_ARG.NO, # type: Union[Any, _ARG]
|
const: Union[Any, _ARG] = _ARG.NO,
|
||||||
choices=_ARG.NO, # type: Union[Sequence[Any], _ARG]
|
choices: Union[Sequence[Any], _ARG] = _ARG.NO,
|
||||||
help=_ARG.NO, # type: Union[str, _ARG]
|
help: Union[str, _ARG] = _ARG.NO,
|
||||||
metavar=_ARG.NO, # type: Union[str, _ARG]
|
metavar: Union[str, _ARG] = _ARG.NO,
|
||||||
# deprecated optparse-only options
|
# deprecated optparse-only options
|
||||||
callback=_ARG.NO, # type: Union[Callable[..., Any], _ARG]
|
callback: Union[Callable[..., Any], _ARG] = _ARG.NO,
|
||||||
callback_args=_ARG.NO, # type: Union[Sequence[Any], _ARG]
|
callback_args: Union[Sequence[Any], _ARG] = _ARG.NO,
|
||||||
callback_kwargs=_ARG.NO, # type: Union[Mapping[str, Any], _ARG]
|
callback_kwargs: Union[Mapping[str, Any], _ARG] = _ARG.NO,
|
||||||
# Options below are taken from argparse.ArgumentParser.add_argument
|
# Options below are taken from argparse.ArgumentParser.add_argument
|
||||||
required=_ARG.NO, # type: Union[bool, _ARG]
|
required: Union[bool, _ARG] = _ARG.NO,
|
||||||
# Options below here are specific to Flake8
|
# Options below here are specific to Flake8
|
||||||
parse_from_config=False, # type: bool
|
parse_from_config: bool = False,
|
||||||
comma_separated_list=False, # type: bool
|
comma_separated_list: bool = False,
|
||||||
normalize_paths=False, # type: bool
|
normalize_paths: bool = False,
|
||||||
): # type: (...) -> None
|
) -> None:
|
||||||
"""Initialize an Option instance.
|
"""Initialize an Option instance.
|
||||||
|
|
||||||
The following are all passed directly through to argparse.
|
The following are all passed directly through to argparse.
|
||||||
|
|
@ -203,7 +213,7 @@ class Option(object):
|
||||||
nargs = 0
|
nargs = 0
|
||||||
|
|
||||||
# optparse -> argparse for `type`
|
# optparse -> argparse for `type`
|
||||||
if isinstance(type, utils.string_types):
|
if isinstance(type, str):
|
||||||
LOG.warning(
|
LOG.warning(
|
||||||
"option %s: please update from optparse string `type=` to "
|
"option %s: please update from optparse string `type=` to "
|
||||||
"argparse callable `type=` -- this will be an error in the "
|
"argparse callable `type=` -- this will be an error in the "
|
||||||
|
|
@ -240,7 +250,7 @@ class Option(object):
|
||||||
self.help = help
|
self.help = help
|
||||||
self.metavar = metavar
|
self.metavar = metavar
|
||||||
self.required = required
|
self.required = required
|
||||||
self.option_kwargs = {
|
self.option_kwargs: Dict[str, Union[Any, _ARG]] = {
|
||||||
"action": self.action,
|
"action": self.action,
|
||||||
"default": self.default,
|
"default": self.default,
|
||||||
"type": self.type,
|
"type": self.type,
|
||||||
|
|
@ -254,14 +264,14 @@ class Option(object):
|
||||||
"help": self.help,
|
"help": self.help,
|
||||||
"metavar": self.metavar,
|
"metavar": self.metavar,
|
||||||
"required": self.required,
|
"required": self.required,
|
||||||
} # type: Dict[str, Union[Any, _ARG]]
|
}
|
||||||
|
|
||||||
# Set our custom attributes
|
# Set our custom attributes
|
||||||
self.parse_from_config = parse_from_config
|
self.parse_from_config = parse_from_config
|
||||||
self.comma_separated_list = comma_separated_list
|
self.comma_separated_list = comma_separated_list
|
||||||
self.normalize_paths = normalize_paths
|
self.normalize_paths = normalize_paths
|
||||||
|
|
||||||
self.config_name = None # type: Optional[str]
|
self.config_name: Optional[str] = None
|
||||||
if parse_from_config:
|
if parse_from_config:
|
||||||
if long_option_name is _ARG.NO:
|
if long_option_name is _ARG.NO:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
|
@ -273,26 +283,23 @@ class Option(object):
|
||||||
self._opt = None
|
self._opt = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filtered_option_kwargs(self): # type: () -> Dict[str, Any]
|
def filtered_option_kwargs(self) -> Dict[str, Any]:
|
||||||
"""Return any actually-specified arguments."""
|
"""Return any actually-specified arguments."""
|
||||||
return {
|
return {
|
||||||
k: v for k, v in self.option_kwargs.items() if v is not _ARG.NO
|
k: v for k, v in self.option_kwargs.items() if v is not _ARG.NO
|
||||||
}
|
}
|
||||||
|
|
||||||
def __repr__(self): # type: () -> str # noqa: D105
|
def __repr__(self) -> str: # noqa: D105
|
||||||
parts = []
|
parts = []
|
||||||
for arg in self.option_args:
|
for arg in self.option_args:
|
||||||
parts.append(arg)
|
parts.append(arg)
|
||||||
for k, v in self.filtered_option_kwargs.items():
|
for k, v in self.filtered_option_kwargs.items():
|
||||||
parts.append("{}={!r}".format(k, v))
|
parts.append(f"{k}={v!r}")
|
||||||
return "Option({})".format(", ".join(parts))
|
return f"Option({', '.join(parts)})"
|
||||||
|
|
||||||
def normalize(self, value, *normalize_args):
|
def normalize(self, value: Any, *normalize_args: str) -> Any:
|
||||||
# type: (Any, *str) -> Any
|
|
||||||
"""Normalize the value based on the option configuration."""
|
"""Normalize the value based on the option configuration."""
|
||||||
if self.comma_separated_list and isinstance(
|
if self.comma_separated_list and isinstance(value, str):
|
||||||
value, utils.string_types
|
|
||||||
):
|
|
||||||
value = utils.parse_comma_separated_list(value)
|
value = utils.parse_comma_separated_list(value)
|
||||||
|
|
||||||
if self.normalize_paths:
|
if self.normalize_paths:
|
||||||
|
|
@ -303,8 +310,9 @@ class Option(object):
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def normalize_from_setuptools(self, value):
|
def normalize_from_setuptools(
|
||||||
# type: (str) -> Union[int, float, complex, bool, str]
|
self, value: str
|
||||||
|
) -> Union[int, float, complex, bool, str]:
|
||||||
"""Normalize the value received from setuptools."""
|
"""Normalize the value received from setuptools."""
|
||||||
value = self.normalize(value)
|
value = self.normalize(value)
|
||||||
if self.type is int or self.action == "count":
|
if self.type is int or self.action == "count":
|
||||||
|
|
@ -321,13 +329,12 @@ class Option(object):
|
||||||
return False
|
return False
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def to_argparse(self):
|
def to_argparse(self) -> Tuple[List[str], Dict[str, Any]]:
|
||||||
# type: () -> Tuple[List[str], Dict[str, Any]]
|
|
||||||
"""Convert a Flake8 Option to argparse ``add_argument`` arguments."""
|
"""Convert a Flake8 Option to argparse ``add_argument`` arguments."""
|
||||||
return self.option_args, self.filtered_option_kwargs
|
return self.option_args, self.filtered_option_kwargs
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def to_optparse(self): # type: () -> NoReturn
|
def to_optparse(self) -> "NoReturn":
|
||||||
"""No longer functional."""
|
"""No longer functional."""
|
||||||
raise AttributeError("to_optparse: flake8 now uses argparse")
|
raise AttributeError("to_optparse: flake8 now uses argparse")
|
||||||
|
|
||||||
|
|
@ -337,16 +344,16 @@ PluginVersion = collections.namedtuple(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class OptionManager(object):
|
class OptionManager:
|
||||||
"""Manage Options and OptionParser while adding post-processing."""
|
"""Manage Options and OptionParser while adding post-processing."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
prog,
|
prog: str,
|
||||||
version,
|
version: str,
|
||||||
usage="%(prog)s [options] file file ...",
|
usage: str = "%(prog)s [options] file file ...",
|
||||||
parents=None,
|
parents: Optional[List[argparse.ArgumentParser]] = None,
|
||||||
): # type: (str, str, str, Optional[List[argparse.ArgumentParser]]) -> None # noqa: E501
|
) -> None: # noqa: E501
|
||||||
"""Initialize an instance of an OptionManager.
|
"""Initialize an instance of an OptionManager.
|
||||||
|
|
||||||
:param str prog:
|
:param str prog:
|
||||||
|
|
@ -362,10 +369,10 @@ class OptionManager(object):
|
||||||
if parents is None:
|
if parents is None:
|
||||||
parents = []
|
parents = []
|
||||||
|
|
||||||
self.parser = argparse.ArgumentParser(
|
self.parser: argparse.ArgumentParser = argparse.ArgumentParser(
|
||||||
prog=prog, usage=usage, parents=parents
|
prog=prog, usage=usage, parents=parents
|
||||||
) # type: argparse.ArgumentParser
|
)
|
||||||
self._current_group = None # type: Optional[argparse._ArgumentGroup]
|
self._current_group: Optional[argparse._ArgumentGroup] = None
|
||||||
self.version_action = cast(
|
self.version_action = cast(
|
||||||
"argparse._VersionAction",
|
"argparse._VersionAction",
|
||||||
self.parser.add_argument(
|
self.parser.add_argument(
|
||||||
|
|
@ -373,16 +380,16 @@ class OptionManager(object):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
self.parser.add_argument("filenames", nargs="*", metavar="filename")
|
self.parser.add_argument("filenames", nargs="*", metavar="filename")
|
||||||
self.config_options_dict = {} # type: Dict[str, Option]
|
self.config_options_dict: Dict[str, Option] = {}
|
||||||
self.options = [] # type: List[Option]
|
self.options: List[Option] = []
|
||||||
self.program_name = prog
|
self.program_name = prog
|
||||||
self.version = version
|
self.version = version
|
||||||
self.registered_plugins = set() # type: Set[PluginVersion]
|
self.registered_plugins: Set[PluginVersion] = set()
|
||||||
self.extended_default_ignore = set() # type: Set[str]
|
self.extended_default_ignore: Set[str] = set()
|
||||||
self.extended_default_select = set() # type: Set[str]
|
self.extended_default_select: Set[str] = set()
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def group(self, name): # type: (str) -> Generator[None, None, None]
|
def group(self, name: str) -> Generator[None, None, None]:
|
||||||
"""Attach options to an argparse group during this context."""
|
"""Attach options to an argparse group during this context."""
|
||||||
group = self.parser.add_argument_group(name)
|
group = self.parser.add_argument_group(name)
|
||||||
self._current_group, orig_group = group, self._current_group
|
self._current_group, orig_group = group, self._current_group
|
||||||
|
|
@ -391,7 +398,7 @@ class OptionManager(object):
|
||||||
finally:
|
finally:
|
||||||
self._current_group = orig_group
|
self._current_group = orig_group
|
||||||
|
|
||||||
def add_option(self, *args, **kwargs): # type: (*Any, **Any) -> None
|
def add_option(self, *args: Any, **kwargs: Any) -> None:
|
||||||
"""Create and register a new option.
|
"""Create and register a new option.
|
||||||
|
|
||||||
See parameters for :class:`~flake8.options.manager.Option` for
|
See parameters for :class:`~flake8.options.manager.Option` for
|
||||||
|
|
@ -416,8 +423,7 @@ class OptionManager(object):
|
||||||
self.config_options_dict[name.replace("_", "-")] = option
|
self.config_options_dict[name.replace("_", "-")] = option
|
||||||
LOG.debug('Registered option "%s".', option)
|
LOG.debug('Registered option "%s".', option)
|
||||||
|
|
||||||
def remove_from_default_ignore(self, error_codes):
|
def remove_from_default_ignore(self, error_codes: Sequence[str]) -> None:
|
||||||
# type: (Sequence[str]) -> None
|
|
||||||
"""Remove specified error codes from the default ignore list.
|
"""Remove specified error codes from the default ignore list.
|
||||||
|
|
||||||
:param list error_codes:
|
:param list error_codes:
|
||||||
|
|
@ -435,8 +441,7 @@ class OptionManager(object):
|
||||||
error_code,
|
error_code,
|
||||||
)
|
)
|
||||||
|
|
||||||
def extend_default_ignore(self, error_codes):
|
def extend_default_ignore(self, error_codes: Sequence[str]) -> None:
|
||||||
# type: (Sequence[str]) -> None
|
|
||||||
"""Extend the default ignore list with the error codes provided.
|
"""Extend the default ignore list with the error codes provided.
|
||||||
|
|
||||||
:param list error_codes:
|
:param list error_codes:
|
||||||
|
|
@ -446,8 +451,7 @@ class OptionManager(object):
|
||||||
LOG.debug("Extending default ignore list with %r", error_codes)
|
LOG.debug("Extending default ignore list with %r", error_codes)
|
||||||
self.extended_default_ignore.update(error_codes)
|
self.extended_default_ignore.update(error_codes)
|
||||||
|
|
||||||
def extend_default_select(self, error_codes):
|
def extend_default_select(self, error_codes: Sequence[str]) -> None:
|
||||||
# type: (Sequence[str]) -> None
|
|
||||||
"""Extend the default select list with the error codes provided.
|
"""Extend the default select list with the error codes provided.
|
||||||
|
|
||||||
:param list error_codes:
|
:param list error_codes:
|
||||||
|
|
@ -458,22 +462,21 @@ class OptionManager(object):
|
||||||
self.extended_default_select.update(error_codes)
|
self.extended_default_select.update(error_codes)
|
||||||
|
|
||||||
def generate_versions(
|
def generate_versions(
|
||||||
self, format_str="%(name)s: %(version)s", join_on=", "
|
self, format_str: str = "%(name)s: %(version)s", join_on: str = ", "
|
||||||
):
|
) -> str:
|
||||||
# type: (str, str) -> str
|
|
||||||
"""Generate a comma-separated list of versions of plugins."""
|
"""Generate a comma-separated list of versions of plugins."""
|
||||||
return join_on.join(
|
return join_on.join(
|
||||||
format_str % plugin._asdict()
|
format_str % plugin._asdict()
|
||||||
for plugin in sorted(self.registered_plugins)
|
for plugin in sorted(self.registered_plugins)
|
||||||
)
|
)
|
||||||
|
|
||||||
def update_version_string(self): # type: () -> None
|
def update_version_string(self) -> None:
|
||||||
"""Update the flake8 version string."""
|
"""Update the flake8 version string."""
|
||||||
self.version_action.version = "{} ({}) {}".format(
|
self.version_action.version = "{} ({}) {}".format(
|
||||||
self.version, self.generate_versions(), utils.get_python_version()
|
self.version, self.generate_versions(), utils.get_python_version()
|
||||||
)
|
)
|
||||||
|
|
||||||
def generate_epilog(self): # type: () -> None
|
def generate_epilog(self) -> None:
|
||||||
"""Create an epilog with the version and name of each of plugin."""
|
"""Create an epilog with the version and name of each of plugin."""
|
||||||
plugin_version_format = "%(name)s: %(version)s"
|
plugin_version_format = "%(name)s: %(version)s"
|
||||||
self.parser.epilog = "Installed plugins: " + self.generate_versions(
|
self.parser.epilog = "Installed plugins: " + self.generate_versions(
|
||||||
|
|
@ -482,10 +485,9 @@ class OptionManager(object):
|
||||||
|
|
||||||
def parse_args(
|
def parse_args(
|
||||||
self,
|
self,
|
||||||
args=None, # type: Optional[List[str]]
|
args: Optional[List[str]] = None,
|
||||||
values=None, # type: Optional[argparse.Namespace]
|
values: Optional[argparse.Namespace] = None,
|
||||||
):
|
) -> Tuple[argparse.Namespace, List[str]]:
|
||||||
# type: (...) -> Tuple[argparse.Namespace, List[str]]
|
|
||||||
"""Proxy to calling the OptionParser's parse_args method."""
|
"""Proxy to calling the OptionParser's parse_args method."""
|
||||||
self.generate_epilog()
|
self.generate_epilog()
|
||||||
self.update_version_string()
|
self.update_version_string()
|
||||||
|
|
@ -495,8 +497,9 @@ class OptionManager(object):
|
||||||
# TODO: refactor callers to not need this
|
# TODO: refactor callers to not need this
|
||||||
return parsed_args, parsed_args.filenames
|
return parsed_args, parsed_args.filenames
|
||||||
|
|
||||||
def parse_known_args(self, args=None):
|
def parse_known_args(
|
||||||
# type: (Optional[List[str]]) -> Tuple[argparse.Namespace, List[str]]
|
self, args: Optional[List[str]] = None
|
||||||
|
) -> Tuple[argparse.Namespace, List[str]]:
|
||||||
"""Parse only the known arguments from the argument values.
|
"""Parse only the known arguments from the argument values.
|
||||||
|
|
||||||
Replicate a little argparse behaviour while we're still on
|
Replicate a little argparse behaviour while we're still on
|
||||||
|
|
@ -506,8 +509,9 @@ class OptionManager(object):
|
||||||
self.update_version_string()
|
self.update_version_string()
|
||||||
return self.parser.parse_known_args(args)
|
return self.parser.parse_known_args(args)
|
||||||
|
|
||||||
def register_plugin(self, name, version, local=False):
|
def register_plugin(
|
||||||
# type: (str, str, bool) -> None
|
self, name: str, version: str, local: bool = False
|
||||||
|
) -> None:
|
||||||
"""Register a plugin relying on the OptionManager.
|
"""Register a plugin relying on the OptionManager.
|
||||||
|
|
||||||
:param str name:
|
:param str name:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
"""Plugin loading and management logic and classes."""
|
"""Plugin loading and management logic and classes."""
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Dict, List, Optional, Set
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from flake8 import exceptions
|
from flake8 import exceptions
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
|
|
@ -13,7 +17,7 @@ __all__ = ("Checkers", "Plugin", "PluginManager", "ReportFormatters")
|
||||||
NO_GROUP_FOUND = object()
|
NO_GROUP_FOUND = object()
|
||||||
|
|
||||||
|
|
||||||
class Plugin(object):
|
class Plugin:
|
||||||
"""Wrap an EntryPoint from setuptools and other logic."""
|
"""Wrap an EntryPoint from setuptools and other logic."""
|
||||||
|
|
||||||
def __init__(self, name, entry_point, local=False):
|
def __init__(self, name, entry_point, local=False):
|
||||||
|
|
@ -31,16 +35,16 @@ class Plugin(object):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.entry_point = entry_point
|
self.entry_point = entry_point
|
||||||
self.local = local
|
self.local = local
|
||||||
self._plugin = None # type: Any
|
self._plugin: Any = None
|
||||||
self._parameters = None
|
self._parameters = None
|
||||||
self._parameter_names = None # type: Optional[List[str]]
|
self._parameter_names: Optional[List[str]] = None
|
||||||
self._group = None
|
self._group = None
|
||||||
self._plugin_name = None
|
self._plugin_name = None
|
||||||
self._version = None
|
self._version = None
|
||||||
|
|
||||||
def __repr__(self): # type: () -> str
|
def __repr__(self) -> str:
|
||||||
"""Provide an easy to read description of the current plugin."""
|
"""Provide an easy to read description of the current plugin."""
|
||||||
return 'Plugin(name="{0}", entry_point="{1}")'.format(
|
return 'Plugin(name="{}", entry_point="{}")'.format(
|
||||||
self.name, self.entry_point.value
|
self.name, self.entry_point.value
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -84,7 +88,7 @@ class Plugin(object):
|
||||||
return self._parameters
|
return self._parameters
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parameter_names(self): # type: () -> List[str]
|
def parameter_names(self) -> List[str]:
|
||||||
"""List of argument names that need to be passed to the plugin."""
|
"""List of argument names that need to be passed to the plugin."""
|
||||||
if self._parameter_names is None:
|
if self._parameter_names is None:
|
||||||
self._parameter_names = list(self.parameters)
|
self._parameter_names = list(self.parameters)
|
||||||
|
|
@ -100,7 +104,7 @@ class Plugin(object):
|
||||||
return self._plugin
|
return self._plugin
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def version(self): # type: () -> str
|
def version(self) -> str:
|
||||||
"""Return the version of the plugin."""
|
"""Return the version of the plugin."""
|
||||||
version = self._version
|
version = self._version
|
||||||
if version is None:
|
if version is None:
|
||||||
|
|
@ -134,9 +138,9 @@ class Plugin(object):
|
||||||
self._plugin = self.entry_point.load()
|
self._plugin = self.entry_point.load()
|
||||||
if not callable(self._plugin):
|
if not callable(self._plugin):
|
||||||
msg = (
|
msg = (
|
||||||
"Plugin %r is not a callable. It might be written for an"
|
f"Plugin {self._plugin!r} is not a callable. It might be "
|
||||||
" older version of flake8 and might not work with this"
|
f"written for an older version of flake8 and might not work "
|
||||||
" version" % self._plugin
|
f"with this version"
|
||||||
)
|
)
|
||||||
LOG.critical(msg)
|
LOG.critical(msg)
|
||||||
raise TypeError(msg)
|
raise TypeError(msg)
|
||||||
|
|
@ -219,11 +223,12 @@ class Plugin(object):
|
||||||
self.disable(optmanager)
|
self.disable(optmanager)
|
||||||
|
|
||||||
|
|
||||||
class PluginManager(object): # pylint: disable=too-few-public-methods
|
class PluginManager: # pylint: disable=too-few-public-methods
|
||||||
"""Find and manage plugins consistently."""
|
"""Find and manage plugins consistently."""
|
||||||
|
|
||||||
def __init__(self, namespace, local_plugins=None):
|
def __init__(
|
||||||
# type: (str, Optional[List[str]]) -> None
|
self, namespace: str, local_plugins: Optional[List[str]] = None
|
||||||
|
) -> None:
|
||||||
"""Initialize the manager.
|
"""Initialize the manager.
|
||||||
|
|
||||||
:param str namespace:
|
:param str namespace:
|
||||||
|
|
@ -232,8 +237,8 @@ class PluginManager(object): # pylint: disable=too-few-public-methods
|
||||||
Plugins from config (as "X = path.to:Plugin" strings).
|
Plugins from config (as "X = path.to:Plugin" strings).
|
||||||
"""
|
"""
|
||||||
self.namespace = namespace
|
self.namespace = namespace
|
||||||
self.plugins = {} # type: Dict[str, Plugin]
|
self.plugins: Dict[str, Plugin] = {}
|
||||||
self.names = [] # type: List[str]
|
self.names: List[str] = []
|
||||||
self._load_local_plugins(local_plugins or [])
|
self._load_local_plugins(local_plugins or [])
|
||||||
self._load_entrypoint_plugins()
|
self._load_entrypoint_plugins()
|
||||||
|
|
||||||
|
|
@ -310,7 +315,7 @@ class PluginManager(object): # pylint: disable=too-few-public-methods
|
||||||
:rtype:
|
:rtype:
|
||||||
tuple
|
tuple
|
||||||
"""
|
"""
|
||||||
plugins_seen = set() # type: Set[str]
|
plugins_seen: Set[str] = set()
|
||||||
for entry_point_name in self.names:
|
for entry_point_name in self.names:
|
||||||
plugin = self.plugins[entry_point_name]
|
plugin = self.plugins[entry_point_name]
|
||||||
plugin_name = plugin.plugin_name
|
plugin_name = plugin.plugin_name
|
||||||
|
|
@ -342,10 +347,10 @@ def version_for(plugin):
|
||||||
return getattr(module, "__version__", None)
|
return getattr(module, "__version__", None)
|
||||||
|
|
||||||
|
|
||||||
class PluginTypeManager(object):
|
class PluginTypeManager:
|
||||||
"""Parent class for most of the specific plugin types."""
|
"""Parent class for most of the specific plugin types."""
|
||||||
|
|
||||||
namespace = None # type: str
|
namespace: str
|
||||||
|
|
||||||
def __init__(self, local_plugins=None):
|
def __init__(self, local_plugins=None):
|
||||||
"""Initialize the plugin type's manager.
|
"""Initialize the plugin type's manager.
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,11 @@
|
||||||
"""Plugin built-in to Flake8 to treat pyflakes as a plugin."""
|
"""Plugin built-in to Flake8 to treat pyflakes as a plugin."""
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import pyflakes
|
|
||||||
import pyflakes.checker
|
import pyflakes.checker
|
||||||
|
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
|
|
||||||
|
|
||||||
FLAKE8_PYFLAKES_CODES = {
|
FLAKE8_PYFLAKES_CODES = {
|
||||||
"UnusedImport": "F401",
|
"UnusedImport": "F401",
|
||||||
"ImportShadowedByLoopVar": "F402",
|
"ImportShadowedByLoopVar": "F402",
|
||||||
|
|
@ -69,8 +64,8 @@ class FlakesChecker(pyflakes.checker.Checker):
|
||||||
name = "pyflakes"
|
name = "pyflakes"
|
||||||
version = pyflakes.__version__
|
version = pyflakes.__version__
|
||||||
with_doctest = False
|
with_doctest = False
|
||||||
include_in_doctest = [] # type: List[str]
|
include_in_doctest: List[str] = []
|
||||||
exclude_from_doctest = [] # type: List[str]
|
exclude_from_doctest: List[str] = []
|
||||||
|
|
||||||
def __init__(self, tree, file_tokens, filename):
|
def __init__(self, tree, file_tokens, filename):
|
||||||
"""Initialize the PyFlakes plugin with an AST tree and filename."""
|
"""Initialize the PyFlakes plugin with an AST tree and filename."""
|
||||||
|
|
@ -96,7 +91,7 @@ class FlakesChecker(pyflakes.checker.Checker):
|
||||||
if overlaped_by:
|
if overlaped_by:
|
||||||
with_doctest = True
|
with_doctest = True
|
||||||
|
|
||||||
super(FlakesChecker, self).__init__(
|
super().__init__(
|
||||||
tree,
|
tree,
|
||||||
filename=filename,
|
filename=filename,
|
||||||
withDoctest=with_doctest,
|
withDoctest=with_doctest,
|
||||||
|
|
@ -150,7 +145,7 @@ class FlakesChecker(pyflakes.checker.Checker):
|
||||||
if included_file == "":
|
if included_file == "":
|
||||||
continue
|
continue
|
||||||
if not included_file.startswith((os.sep, "./", "~/")):
|
if not included_file.startswith((os.sep, "./", "~/")):
|
||||||
included_files.append("./" + included_file)
|
included_files.append(f"./{included_file}")
|
||||||
else:
|
else:
|
||||||
included_files.append(included_file)
|
included_files.append(included_file)
|
||||||
cls.include_in_doctest = utils.normalize_paths(included_files)
|
cls.include_in_doctest = utils.normalize_paths(included_files)
|
||||||
|
|
@ -160,7 +155,7 @@ class FlakesChecker(pyflakes.checker.Checker):
|
||||||
if excluded_file == "":
|
if excluded_file == "":
|
||||||
continue
|
continue
|
||||||
if not excluded_file.startswith((os.sep, "./", "~/")):
|
if not excluded_file.startswith((os.sep, "./", "~/")):
|
||||||
excluded_files.append("./" + excluded_file)
|
excluded_files.append(f"./{excluded_file}")
|
||||||
else:
|
else:
|
||||||
excluded_files.append(excluded_file)
|
excluded_files.append(excluded_file)
|
||||||
cls.exclude_from_doctest = utils.normalize_paths(excluded_files)
|
cls.exclude_from_doctest = utils.normalize_paths(excluded_files)
|
||||||
|
|
@ -170,10 +165,10 @@ class FlakesChecker(pyflakes.checker.Checker):
|
||||||
)
|
)
|
||||||
if inc_exc:
|
if inc_exc:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'"%s" was specified in both the '
|
f"{inc_exc!r} was specified in both the "
|
||||||
"include-in-doctest and exclude-from-doctest "
|
f"include-in-doctest and exclude-from-doctest "
|
||||||
"options. You are not allowed to specify it in "
|
f"options. You are not allowed to specify it in "
|
||||||
"both for doctesting." % inc_exc
|
f"both for doctesting."
|
||||||
)
|
)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,13 @@ import argparse
|
||||||
import ast
|
import ast
|
||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import sys
|
|
||||||
import tokenize
|
import tokenize
|
||||||
from typing import Any, Dict, Generator, List, Optional, Tuple
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Generator
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
import flake8
|
import flake8
|
||||||
from flake8 import defaults
|
from flake8 import defaults
|
||||||
|
|
@ -25,7 +29,7 @@ _LogicalMapping = List[Tuple[int, Tuple[int, int]]]
|
||||||
_Logical = Tuple[List[str], List[str], _LogicalMapping]
|
_Logical = Tuple[List[str], List[str], _LogicalMapping]
|
||||||
|
|
||||||
|
|
||||||
class FileProcessor(object):
|
class FileProcessor:
|
||||||
"""Processes a file and holdes state.
|
"""Processes a file and holdes state.
|
||||||
|
|
||||||
This processes a file by generating tokens, logical and physical lines,
|
This processes a file by generating tokens, logical and physical lines,
|
||||||
|
|
@ -56,8 +60,12 @@ class FileProcessor(object):
|
||||||
#: always ``False``, included for compatibility
|
#: always ``False``, included for compatibility
|
||||||
noqa = False
|
noqa = False
|
||||||
|
|
||||||
def __init__(self, filename, options, lines=None):
|
def __init__(
|
||||||
# type: (str, argparse.Namespace, Optional[List[str]]) -> None
|
self,
|
||||||
|
filename: str,
|
||||||
|
options: argparse.Namespace,
|
||||||
|
lines: Optional[List[str]] = None,
|
||||||
|
) -> None:
|
||||||
"""Initialice our file processor.
|
"""Initialice our file processor.
|
||||||
|
|
||||||
:param str filename:
|
:param str filename:
|
||||||
|
|
@ -74,13 +82,13 @@ class FileProcessor(object):
|
||||||
#: Number of blank lines
|
#: Number of blank lines
|
||||||
self.blank_lines = 0
|
self.blank_lines = 0
|
||||||
#: Checker states for each plugin?
|
#: Checker states for each plugin?
|
||||||
self._checker_states = {} # type: Dict[str, Dict[Any, Any]]
|
self._checker_states: Dict[str, Dict[Any, Any]] = {}
|
||||||
#: Current checker state
|
#: Current checker state
|
||||||
self.checker_state = {} # type: Dict[Any, Any]
|
self.checker_state: Dict[Any, Any] = {}
|
||||||
#: User provided option for hang closing
|
#: User provided option for hang closing
|
||||||
self.hang_closing = options.hang_closing
|
self.hang_closing = options.hang_closing
|
||||||
#: Character used for indentation
|
#: Character used for indentation
|
||||||
self.indent_char = None # type: Optional[str]
|
self.indent_char: Optional[str] = None
|
||||||
#: Current level of indentation
|
#: Current level of indentation
|
||||||
self.indent_level = 0
|
self.indent_level = 0
|
||||||
#: Number of spaces used for indentation
|
#: Number of spaces used for indentation
|
||||||
|
|
@ -104,19 +112,19 @@ class FileProcessor(object):
|
||||||
#: Previous unindented (i.e. top-level) logical line
|
#: Previous unindented (i.e. top-level) logical line
|
||||||
self.previous_unindented_logical_line = ""
|
self.previous_unindented_logical_line = ""
|
||||||
#: Current set of tokens
|
#: Current set of tokens
|
||||||
self.tokens = [] # type: List[_Token]
|
self.tokens: List[_Token] = []
|
||||||
#: Total number of lines in the file
|
#: Total number of lines in the file
|
||||||
self.total_lines = len(self.lines)
|
self.total_lines = len(self.lines)
|
||||||
#: Verbosity level of Flake8
|
#: Verbosity level of Flake8
|
||||||
self.verbose = options.verbose
|
self.verbose = options.verbose
|
||||||
#: Statistics dictionary
|
#: Statistics dictionary
|
||||||
self.statistics = {"logical lines": 0}
|
self.statistics = {"logical lines": 0}
|
||||||
self._file_tokens = None # type: Optional[List[_Token]]
|
self._file_tokens: Optional[List[_Token]] = None
|
||||||
# map from line number to the line we'll search for `noqa` in
|
# map from line number to the line we'll search for `noqa` in
|
||||||
self._noqa_line_mapping = None # type: Optional[Dict[int, str]]
|
self._noqa_line_mapping: Optional[Dict[int, str]] = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def file_tokens(self): # type: () -> List[_Token]
|
def file_tokens(self) -> List[_Token]:
|
||||||
"""Return the complete set of tokens for a file.
|
"""Return the complete set of tokens for a file.
|
||||||
|
|
||||||
Accessing this attribute *may* raise an InvalidSyntax exception.
|
Accessing this attribute *may* raise an InvalidSyntax exception.
|
||||||
|
|
@ -135,28 +143,28 @@ class FileProcessor(object):
|
||||||
return self._file_tokens
|
return self._file_tokens
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def inside_multiline(self, line_number):
|
def inside_multiline(
|
||||||
# type: (int) -> Generator[None, None, None]
|
self, line_number: int
|
||||||
|
) -> Generator[None, None, None]:
|
||||||
"""Context-manager to toggle the multiline attribute."""
|
"""Context-manager to toggle the multiline attribute."""
|
||||||
self.line_number = line_number
|
self.line_number = line_number
|
||||||
self.multiline = True
|
self.multiline = True
|
||||||
yield
|
yield
|
||||||
self.multiline = False
|
self.multiline = False
|
||||||
|
|
||||||
def reset_blank_before(self): # type: () -> None
|
def reset_blank_before(self) -> None:
|
||||||
"""Reset the blank_before attribute to zero."""
|
"""Reset the blank_before attribute to zero."""
|
||||||
self.blank_before = 0
|
self.blank_before = 0
|
||||||
|
|
||||||
def delete_first_token(self): # type: () -> None
|
def delete_first_token(self) -> None:
|
||||||
"""Delete the first token in the list of tokens."""
|
"""Delete the first token in the list of tokens."""
|
||||||
del self.tokens[0]
|
del self.tokens[0]
|
||||||
|
|
||||||
def visited_new_blank_line(self): # type: () -> None
|
def visited_new_blank_line(self) -> None:
|
||||||
"""Note that we visited a new blank line."""
|
"""Note that we visited a new blank line."""
|
||||||
self.blank_lines += 1
|
self.blank_lines += 1
|
||||||
|
|
||||||
def update_state(self, mapping):
|
def update_state(self, mapping: _LogicalMapping) -> None:
|
||||||
# type: (_LogicalMapping) -> None
|
|
||||||
"""Update the indent level based on the logical line mapping."""
|
"""Update the indent level based on the logical line mapping."""
|
||||||
(start_row, start_col) = mapping[0][1]
|
(start_row, start_col) = mapping[0][1]
|
||||||
start_line = self.lines[start_row - 1]
|
start_line = self.lines[start_row - 1]
|
||||||
|
|
@ -164,15 +172,14 @@ class FileProcessor(object):
|
||||||
if self.blank_before < self.blank_lines:
|
if self.blank_before < self.blank_lines:
|
||||||
self.blank_before = self.blank_lines
|
self.blank_before = self.blank_lines
|
||||||
|
|
||||||
def update_checker_state_for(self, plugin):
|
def update_checker_state_for(self, plugin: Dict[str, Any]) -> None:
|
||||||
# type: (Dict[str, Any]) -> None
|
|
||||||
"""Update the checker_state attribute for the plugin."""
|
"""Update the checker_state attribute for the plugin."""
|
||||||
if "checker_state" in plugin["parameters"]:
|
if "checker_state" in plugin["parameters"]:
|
||||||
self.checker_state = self._checker_states.setdefault(
|
self.checker_state = self._checker_states.setdefault(
|
||||||
plugin["name"], {}
|
plugin["name"], {}
|
||||||
)
|
)
|
||||||
|
|
||||||
def next_logical_line(self): # type: () -> None
|
def next_logical_line(self) -> None:
|
||||||
"""Record the previous logical line.
|
"""Record the previous logical line.
|
||||||
|
|
||||||
This also resets the tokens list and the blank_lines count.
|
This also resets the tokens list and the blank_lines count.
|
||||||
|
|
@ -185,11 +192,11 @@ class FileProcessor(object):
|
||||||
self.blank_lines = 0
|
self.blank_lines = 0
|
||||||
self.tokens = []
|
self.tokens = []
|
||||||
|
|
||||||
def build_logical_line_tokens(self): # type: () -> _Logical
|
def build_logical_line_tokens(self) -> _Logical:
|
||||||
"""Build the mapping, comments, and logical line lists."""
|
"""Build the mapping, comments, and logical line lists."""
|
||||||
logical = []
|
logical = []
|
||||||
comments = []
|
comments = []
|
||||||
mapping = [] # type: _LogicalMapping
|
mapping: _LogicalMapping = []
|
||||||
length = 0
|
length = 0
|
||||||
previous_row = previous_column = None
|
previous_row = previous_column = None
|
||||||
for token_type, text, start, end, line in self.tokens:
|
for token_type, text, start, end, line in self.tokens:
|
||||||
|
|
@ -211,7 +218,7 @@ class FileProcessor(object):
|
||||||
if previous_text == "," or (
|
if previous_text == "," or (
|
||||||
previous_text not in "{[(" and text not in "}])"
|
previous_text not in "{[(" and text not in "}])"
|
||||||
):
|
):
|
||||||
text = " " + text
|
text = f" {text}"
|
||||||
elif previous_column != start_column:
|
elif previous_column != start_column:
|
||||||
text = line[previous_column:start_column] + text
|
text = line[previous_column:start_column] + text
|
||||||
logical.append(text)
|
logical.append(text)
|
||||||
|
|
@ -220,12 +227,11 @@ class FileProcessor(object):
|
||||||
(previous_row, previous_column) = end
|
(previous_row, previous_column) = end
|
||||||
return comments, logical, mapping
|
return comments, logical, mapping
|
||||||
|
|
||||||
def build_ast(self): # type: () -> ast.AST
|
def build_ast(self) -> ast.AST:
|
||||||
"""Build an abstract syntax tree from the list of lines."""
|
"""Build an abstract syntax tree from the list of lines."""
|
||||||
return ast.parse("".join(self.lines))
|
return ast.parse("".join(self.lines))
|
||||||
|
|
||||||
def build_logical_line(self):
|
def build_logical_line(self) -> Tuple[str, str, _LogicalMapping]:
|
||||||
# type: () -> Tuple[str, str, _LogicalMapping]
|
|
||||||
"""Build a logical line from the current tokens list."""
|
"""Build a logical line from the current tokens list."""
|
||||||
comments, logical, mapping_list = self.build_logical_line_tokens()
|
comments, logical, mapping_list = self.build_logical_line_tokens()
|
||||||
joined_comments = "".join(comments)
|
joined_comments = "".join(comments)
|
||||||
|
|
@ -233,8 +239,7 @@ class FileProcessor(object):
|
||||||
self.statistics["logical lines"] += 1
|
self.statistics["logical lines"] += 1
|
||||||
return joined_comments, self.logical_line, mapping_list
|
return joined_comments, self.logical_line, mapping_list
|
||||||
|
|
||||||
def split_line(self, token):
|
def split_line(self, token: _Token) -> Generator[str, None, None]:
|
||||||
# type: (_Token) -> Generator[str, None, None]
|
|
||||||
"""Split a physical line's line based on new-lines.
|
"""Split a physical line's line based on new-lines.
|
||||||
|
|
||||||
This also auto-increments the line number for the caller.
|
This also auto-increments the line number for the caller.
|
||||||
|
|
@ -243,8 +248,11 @@ class FileProcessor(object):
|
||||||
yield line
|
yield line
|
||||||
self.line_number += 1
|
self.line_number += 1
|
||||||
|
|
||||||
def keyword_arguments_for(self, parameters, arguments=None):
|
def keyword_arguments_for(
|
||||||
# type: (Dict[str, bool], Optional[Dict[str, Any]]) -> Dict[str, Any]
|
self,
|
||||||
|
parameters: Dict[str, bool],
|
||||||
|
arguments: Optional[Dict[str, Any]] = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
"""Generate the keyword arguments for a list of parameters."""
|
"""Generate the keyword arguments for a list of parameters."""
|
||||||
if arguments is None:
|
if arguments is None:
|
||||||
arguments = {}
|
arguments = {}
|
||||||
|
|
@ -265,7 +273,7 @@ class FileProcessor(object):
|
||||||
)
|
)
|
||||||
return arguments
|
return arguments
|
||||||
|
|
||||||
def generate_tokens(self): # type: () -> Generator[_Token, None, None]
|
def generate_tokens(self) -> Generator[_Token, None, None]:
|
||||||
"""Tokenize the file and yield the tokens.
|
"""Tokenize the file and yield the tokens.
|
||||||
|
|
||||||
:raises flake8.exceptions.InvalidSyntax:
|
:raises flake8.exceptions.InvalidSyntax:
|
||||||
|
|
@ -281,13 +289,14 @@ class FileProcessor(object):
|
||||||
except (tokenize.TokenError, SyntaxError) as exc:
|
except (tokenize.TokenError, SyntaxError) as exc:
|
||||||
raise exceptions.InvalidSyntax(exception=exc)
|
raise exceptions.InvalidSyntax(exception=exc)
|
||||||
|
|
||||||
def _noqa_line_range(self, min_line, max_line):
|
def _noqa_line_range(
|
||||||
# type: (int, int) -> Dict[int, str]
|
self, min_line: int, max_line: int
|
||||||
|
) -> Dict[int, str]:
|
||||||
line_range = range(min_line, max_line + 1)
|
line_range = range(min_line, max_line + 1)
|
||||||
joined = "".join(self.lines[min_line - 1 : max_line])
|
joined = "".join(self.lines[min_line - 1 : max_line])
|
||||||
return dict.fromkeys(line_range, joined)
|
return dict.fromkeys(line_range, joined)
|
||||||
|
|
||||||
def noqa_line_for(self, line_number): # type: (int) -> Optional[str]
|
def noqa_line_for(self, line_number: int) -> Optional[str]:
|
||||||
"""Retrieve the line which will be used to determine noqa."""
|
"""Retrieve the line which will be used to determine noqa."""
|
||||||
if self._noqa_line_mapping is None:
|
if self._noqa_line_mapping is None:
|
||||||
try:
|
try:
|
||||||
|
|
@ -327,7 +336,7 @@ class FileProcessor(object):
|
||||||
# retrieve a physical line (since none exist).
|
# retrieve a physical line (since none exist).
|
||||||
return self._noqa_line_mapping.get(line_number)
|
return self._noqa_line_mapping.get(line_number)
|
||||||
|
|
||||||
def next_line(self): # type: () -> str
|
def next_line(self) -> str:
|
||||||
"""Get the next line from the list."""
|
"""Get the next line from the list."""
|
||||||
if self.line_number >= self.total_lines:
|
if self.line_number >= self.total_lines:
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -337,8 +346,7 @@ class FileProcessor(object):
|
||||||
self.indent_char = line[0]
|
self.indent_char = line[0]
|
||||||
return line
|
return line
|
||||||
|
|
||||||
def read_lines(self):
|
def read_lines(self) -> List[str]:
|
||||||
# type: () -> List[str]
|
|
||||||
"""Read the lines for this file checker."""
|
"""Read the lines for this file checker."""
|
||||||
if self.filename is None or self.filename == "-":
|
if self.filename is None or self.filename == "-":
|
||||||
self.filename = self.options.stdin_display_name or "stdin"
|
self.filename = self.options.stdin_display_name or "stdin"
|
||||||
|
|
@ -347,13 +355,8 @@ class FileProcessor(object):
|
||||||
lines = self.read_lines_from_filename()
|
lines = self.read_lines_from_filename()
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def _readlines_py2(self):
|
def read_lines_from_filename(self) -> List[str]:
|
||||||
# type: () -> List[str]
|
"""Read the lines for a file."""
|
||||||
with open(self.filename, "rU") as fd:
|
|
||||||
return fd.readlines()
|
|
||||||
|
|
||||||
def _readlines_py3(self):
|
|
||||||
# type: () -> List[str]
|
|
||||||
try:
|
try:
|
||||||
with tokenize.open(self.filename) as fd:
|
with tokenize.open(self.filename) as fd:
|
||||||
return fd.readlines()
|
return fd.readlines()
|
||||||
|
|
@ -363,22 +366,11 @@ class FileProcessor(object):
|
||||||
with open(self.filename, encoding="latin-1") as fd:
|
with open(self.filename, encoding="latin-1") as fd:
|
||||||
return fd.readlines()
|
return fd.readlines()
|
||||||
|
|
||||||
def read_lines_from_filename(self):
|
def read_lines_from_stdin(self) -> List[str]:
|
||||||
# type: () -> List[str]
|
|
||||||
"""Read the lines for a file."""
|
|
||||||
if (2, 6) <= sys.version_info < (3, 0):
|
|
||||||
readlines = self._readlines_py2
|
|
||||||
elif (3, 0) <= sys.version_info < (4, 0):
|
|
||||||
readlines = self._readlines_py3
|
|
||||||
return readlines()
|
|
||||||
|
|
||||||
def read_lines_from_stdin(self):
|
|
||||||
# type: () -> List[str]
|
|
||||||
"""Read the lines from standard in."""
|
"""Read the lines from standard in."""
|
||||||
return utils.stdin_get_lines()
|
return utils.stdin_get_lines()
|
||||||
|
|
||||||
def should_ignore_file(self):
|
def should_ignore_file(self) -> bool:
|
||||||
# type: () -> bool
|
|
||||||
"""Check if ``flake8: noqa`` is in the file to be ignored.
|
"""Check if ``flake8: noqa`` is in the file to be ignored.
|
||||||
|
|
||||||
:returns:
|
:returns:
|
||||||
|
|
@ -400,8 +392,7 @@ class FileProcessor(object):
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def strip_utf_bom(self):
|
def strip_utf_bom(self) -> None:
|
||||||
# type: () -> None
|
|
||||||
"""Strip the UTF bom from the lines of the file."""
|
"""Strip the UTF bom from the lines of the file."""
|
||||||
if not self.lines:
|
if not self.lines:
|
||||||
# If we have nothing to analyze quit early
|
# If we have nothing to analyze quit early
|
||||||
|
|
@ -418,23 +409,22 @@ class FileProcessor(object):
|
||||||
self.lines[0] = self.lines[0][3:]
|
self.lines[0] = self.lines[0][3:]
|
||||||
|
|
||||||
|
|
||||||
def is_eol_token(token): # type: (_Token) -> bool
|
def is_eol_token(token: _Token) -> bool:
|
||||||
"""Check if the token is an end-of-line token."""
|
"""Check if the token is an end-of-line token."""
|
||||||
return token[0] in NEWLINE or token[4][token[3][1] :].lstrip() == "\\\n"
|
return token[0] in NEWLINE or token[4][token[3][1] :].lstrip() == "\\\n"
|
||||||
|
|
||||||
|
|
||||||
def is_multiline_string(token): # type: (_Token) -> bool
|
def is_multiline_string(token: _Token) -> bool:
|
||||||
"""Check if this is a multiline string."""
|
"""Check if this is a multiline string."""
|
||||||
return token[0] == tokenize.STRING and "\n" in token[1]
|
return token[0] == tokenize.STRING and "\n" in token[1]
|
||||||
|
|
||||||
|
|
||||||
def token_is_newline(token): # type: (_Token) -> bool
|
def token_is_newline(token: _Token) -> bool:
|
||||||
"""Check if the token type is a newline token type."""
|
"""Check if the token type is a newline token type."""
|
||||||
return token[0] in NEWLINE
|
return token[0] in NEWLINE
|
||||||
|
|
||||||
|
|
||||||
def count_parentheses(current_parentheses_count, token_text):
|
def count_parentheses(current_parentheses_count: int, token_text: str) -> int:
|
||||||
# type: (int, str) -> int
|
|
||||||
"""Count the number of parentheses."""
|
"""Count the number of parentheses."""
|
||||||
if token_text in "([{": # nosec
|
if token_text in "([{": # nosec
|
||||||
return current_parentheses_count + 1
|
return current_parentheses_count + 1
|
||||||
|
|
@ -443,12 +433,12 @@ def count_parentheses(current_parentheses_count, token_text):
|
||||||
return current_parentheses_count
|
return current_parentheses_count
|
||||||
|
|
||||||
|
|
||||||
def log_token(log, token): # type: (logging.Logger, _Token) -> None
|
def log_token(log: logging.Logger, token: _Token) -> None:
|
||||||
"""Log a token to a provided logging object."""
|
"""Log a token to a provided logging object."""
|
||||||
if token[2][0] == token[3][0]:
|
if token[2][0] == token[3][0]:
|
||||||
pos = "[%s:%s]" % (token[2][1] or "", token[3][1])
|
pos = "[{}:{}]".format(token[2][1] or "", token[3][1])
|
||||||
else:
|
else:
|
||||||
pos = "l.%s" % token[3][0]
|
pos = f"l.{token[3][0]}"
|
||||||
log.log(
|
log.log(
|
||||||
flake8._EXTRA_VERBOSE,
|
flake8._EXTRA_VERBOSE,
|
||||||
"l.%s\t%s\t%s\t%r"
|
"l.%s\t%s\t%s\t%r"
|
||||||
|
|
@ -458,7 +448,7 @@ def log_token(log, token): # type: (logging.Logger, _Token) -> None
|
||||||
|
|
||||||
# NOTE(sigmavirus24): This was taken wholesale from
|
# NOTE(sigmavirus24): This was taken wholesale from
|
||||||
# https://github.com/PyCQA/pycodestyle
|
# https://github.com/PyCQA/pycodestyle
|
||||||
def expand_indent(line): # type: (str) -> int
|
def expand_indent(line: str) -> int:
|
||||||
r"""Return the amount of indentation.
|
r"""Return the amount of indentation.
|
||||||
|
|
||||||
Tabs are expanded to the next multiple of 8.
|
Tabs are expanded to the next multiple of 8.
|
||||||
|
|
@ -488,7 +478,7 @@ def expand_indent(line): # type: (str) -> int
|
||||||
# NOTE(sigmavirus24): This was taken wholesale from
|
# NOTE(sigmavirus24): This was taken wholesale from
|
||||||
# https://github.com/PyCQA/pycodestyle. The in-line comments were edited to be
|
# https://github.com/PyCQA/pycodestyle. The in-line comments were edited to be
|
||||||
# more descriptive.
|
# more descriptive.
|
||||||
def mutate_string(text): # type: (str) -> str
|
def mutate_string(text: str) -> str:
|
||||||
"""Replace contents with 'xxx' to prevent syntax matching.
|
"""Replace contents with 'xxx' to prevent syntax matching.
|
||||||
|
|
||||||
>>> mutate_string('"abc"')
|
>>> mutate_string('"abc"')
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,23 @@
|
||||||
"""Statistic collection logic for Flake8."""
|
"""Statistic collection logic for Flake8."""
|
||||||
import collections
|
import collections
|
||||||
from typing import Dict, Generator, List, Optional
|
from typing import Dict
|
||||||
|
from typing import Generator
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
if TYPE_CHECKING:
|
||||||
from flake8.style_guide import Violation
|
from flake8.style_guide import Violation
|
||||||
|
|
||||||
|
|
||||||
class Statistics(object):
|
class Statistics:
|
||||||
"""Manager of aggregated statistics for a run of Flake8."""
|
"""Manager of aggregated statistics for a run of Flake8."""
|
||||||
|
|
||||||
def __init__(self): # type: () -> None
|
def __init__(self) -> None:
|
||||||
"""Initialize the underlying dictionary for our statistics."""
|
"""Initialize the underlying dictionary for our statistics."""
|
||||||
self._store = {} # type: Dict[Key, Statistic]
|
self._store: Dict[Key, "Statistic"] = {}
|
||||||
|
|
||||||
def error_codes(self): # type: () -> List[str]
|
def error_codes(self) -> List[str]:
|
||||||
"""Return all unique error codes stored.
|
"""Return all unique error codes stored.
|
||||||
|
|
||||||
:returns:
|
:returns:
|
||||||
|
|
@ -23,7 +27,7 @@ class Statistics(object):
|
||||||
"""
|
"""
|
||||||
return sorted({key.code for key in self._store})
|
return sorted({key.code for key in self._store})
|
||||||
|
|
||||||
def record(self, error): # type: (Violation) -> None
|
def record(self, error: "Violation") -> None:
|
||||||
"""Add the fact that the error was seen in the file.
|
"""Add the fact that the error was seen in the file.
|
||||||
|
|
||||||
:param error:
|
:param error:
|
||||||
|
|
@ -37,8 +41,9 @@ class Statistics(object):
|
||||||
self._store[key] = Statistic.create_from(error)
|
self._store[key] = Statistic.create_from(error)
|
||||||
self._store[key].increment()
|
self._store[key].increment()
|
||||||
|
|
||||||
def statistics_for(self, prefix, filename=None):
|
def statistics_for(
|
||||||
# type: (str, Optional[str]) -> Generator[Statistic, None, None]
|
self, prefix: str, filename: Optional[str] = None
|
||||||
|
) -> Generator["Statistic", None, None]:
|
||||||
"""Generate statistics for the prefix and filename.
|
"""Generate statistics for the prefix and filename.
|
||||||
|
|
||||||
If you have a :class:`Statistics` object that has recorded errors,
|
If you have a :class:`Statistics` object that has recorded errors,
|
||||||
|
|
@ -79,11 +84,11 @@ class Key(collections.namedtuple("Key", ["filename", "code"])):
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_from(cls, error): # type: (Violation) -> Key
|
def create_from(cls, error: "Violation") -> "Key":
|
||||||
"""Create a Key from :class:`flake8.style_guide.Violation`."""
|
"""Create a Key from :class:`flake8.style_guide.Violation`."""
|
||||||
return cls(filename=error.filename, code=error.code)
|
return cls(filename=error.filename, code=error.code)
|
||||||
|
|
||||||
def matches(self, prefix, filename): # type: (str, Optional[str]) -> bool
|
def matches(self, prefix: str, filename: Optional[str]) -> bool:
|
||||||
"""Determine if this key matches some constraints.
|
"""Determine if this key matches some constraints.
|
||||||
|
|
||||||
:param str prefix:
|
:param str prefix:
|
||||||
|
|
@ -102,7 +107,7 @@ class Key(collections.namedtuple("Key", ["filename", "code"])):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Statistic(object):
|
class Statistic:
|
||||||
"""Simple wrapper around the logic of each statistic.
|
"""Simple wrapper around the logic of each statistic.
|
||||||
|
|
||||||
Instead of maintaining a simple but potentially hard to reason about
|
Instead of maintaining a simple but potentially hard to reason about
|
||||||
|
|
@ -110,8 +115,9 @@ class Statistic(object):
|
||||||
convenience methods on it.
|
convenience methods on it.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, error_code, filename, message, count):
|
def __init__(
|
||||||
# type: (str, str, str, int) -> None
|
self, error_code: str, filename: str, message: str, count: int
|
||||||
|
) -> None:
|
||||||
"""Initialize our Statistic."""
|
"""Initialize our Statistic."""
|
||||||
self.error_code = error_code
|
self.error_code = error_code
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
|
|
@ -119,7 +125,7 @@ class Statistic(object):
|
||||||
self.count = count
|
self.count = count
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_from(cls, error): # type: (Violation) -> Statistic
|
def create_from(cls, error: "Violation") -> "Statistic":
|
||||||
"""Create a Statistic from a :class:`flake8.style_guide.Violation`."""
|
"""Create a Statistic from a :class:`flake8.style_guide.Violation`."""
|
||||||
return cls(
|
return cls(
|
||||||
error_code=error.code,
|
error_code=error.code,
|
||||||
|
|
@ -128,6 +134,6 @@ class Statistic(object):
|
||||||
count=0,
|
count=0,
|
||||||
)
|
)
|
||||||
|
|
||||||
def increment(self): # type: () -> None
|
def increment(self) -> None:
|
||||||
"""Increment the number of times we've seen this error in this file."""
|
"""Increment the number of times we've seen this error in this file."""
|
||||||
self.count += 1
|
self.count += 1
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,23 @@ import collections
|
||||||
import contextlib
|
import contextlib
|
||||||
import copy
|
import copy
|
||||||
import enum
|
import enum
|
||||||
|
import functools
|
||||||
import itertools
|
import itertools
|
||||||
import linecache
|
import linecache
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Generator, List, Match, Optional, Sequence, Set
|
from typing import Dict
|
||||||
from typing import Tuple, Union
|
from typing import Generator
|
||||||
|
from typing import List
|
||||||
|
from typing import Match
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Sequence
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from flake8 import defaults
|
from flake8 import defaults
|
||||||
from flake8 import statistics
|
from flake8 import statistics
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
from flake8._compat import lru_cache
|
|
||||||
from flake8.formatting import base as base_formatter
|
from flake8.formatting import base as base_formatter
|
||||||
|
|
||||||
__all__ = ("StyleGuide",)
|
__all__ = ("StyleGuide",)
|
||||||
|
|
@ -42,8 +49,8 @@ class Decision(enum.Enum):
|
||||||
Selected = "selected error"
|
Selected = "selected error"
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=512)
|
@functools.lru_cache(maxsize=512)
|
||||||
def find_noqa(physical_line): # type: (str) -> Optional[Match[str]]
|
def find_noqa(physical_line: str) -> Optional[Match[str]]:
|
||||||
return defaults.NOQA_INLINE_REGEXP.search(physical_line)
|
return defaults.NOQA_INLINE_REGEXP.search(physical_line)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -63,8 +70,7 @@ _Violation = collections.namedtuple(
|
||||||
class Violation(_Violation):
|
class Violation(_Violation):
|
||||||
"""Class representing a violation reported by Flake8."""
|
"""Class representing a violation reported by Flake8."""
|
||||||
|
|
||||||
def is_inline_ignored(self, disable_noqa):
|
def is_inline_ignored(self, disable_noqa: bool) -> bool:
|
||||||
# type: (bool) -> bool
|
|
||||||
"""Determine if a comment has been added to ignore this line.
|
"""Determine if a comment has been added to ignore this line.
|
||||||
|
|
||||||
:param bool disable_noqa:
|
:param bool disable_noqa:
|
||||||
|
|
@ -105,8 +111,7 @@ class Violation(_Violation):
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def is_in(self, diff):
|
def is_in(self, diff: Dict[str, Set[int]]) -> bool:
|
||||||
# type: (Dict[str, Set[int]]) -> bool
|
|
||||||
"""Determine if the violation is included in a diff's line ranges.
|
"""Determine if the violation is included in a diff's line ranges.
|
||||||
|
|
||||||
This function relies on the parsed data added via
|
This function relies on the parsed data added via
|
||||||
|
|
@ -142,16 +147,16 @@ class Violation(_Violation):
|
||||||
return self.line_number in line_numbers
|
return self.line_number in line_numbers
|
||||||
|
|
||||||
|
|
||||||
class DecisionEngine(object):
|
class DecisionEngine:
|
||||||
"""A class for managing the decision process around violations.
|
"""A class for managing the decision process around violations.
|
||||||
|
|
||||||
This contains the logic for whether a violation should be reported or
|
This contains the logic for whether a violation should be reported or
|
||||||
ignored.
|
ignored.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, options): # type: (argparse.Namespace) -> None
|
def __init__(self, options: argparse.Namespace) -> None:
|
||||||
"""Initialize the engine."""
|
"""Initialize the engine."""
|
||||||
self.cache = {} # type: Dict[str, Decision]
|
self.cache: Dict[str, Decision] = {}
|
||||||
self.selected = tuple(options.select)
|
self.selected = tuple(options.select)
|
||||||
self.extended_selected = tuple(
|
self.extended_selected = tuple(
|
||||||
sorted(options.extended_default_select, reverse=True)
|
sorted(options.extended_default_select, reverse=True)
|
||||||
|
|
@ -169,16 +174,15 @@ class DecisionEngine(object):
|
||||||
self.using_default_ignore = set(self.ignored) == set(defaults.IGNORE)
|
self.using_default_ignore = set(self.ignored) == set(defaults.IGNORE)
|
||||||
self.using_default_select = set(self.selected) == set(defaults.SELECT)
|
self.using_default_select = set(self.selected) == set(defaults.SELECT)
|
||||||
|
|
||||||
def _in_all_selected(self, code): # type: (str) -> bool
|
def _in_all_selected(self, code: str) -> bool:
|
||||||
return bool(self.all_selected) and code.startswith(self.all_selected)
|
return bool(self.all_selected) and code.startswith(self.all_selected)
|
||||||
|
|
||||||
def _in_extended_selected(self, code): # type: (str) -> bool
|
def _in_extended_selected(self, code: str) -> bool:
|
||||||
return bool(self.extended_selected) and code.startswith(
|
return bool(self.extended_selected) and code.startswith(
|
||||||
self.extended_selected
|
self.extended_selected
|
||||||
)
|
)
|
||||||
|
|
||||||
def was_selected(self, code):
|
def was_selected(self, code: str) -> Union[Selected, Ignored]:
|
||||||
# type: (str) -> Union[Selected, Ignored]
|
|
||||||
"""Determine if the code has been selected by the user.
|
"""Determine if the code has been selected by the user.
|
||||||
|
|
||||||
:param str code:
|
:param str code:
|
||||||
|
|
@ -201,8 +205,7 @@ class DecisionEngine(object):
|
||||||
|
|
||||||
return Ignored.Implicitly
|
return Ignored.Implicitly
|
||||||
|
|
||||||
def was_ignored(self, code):
|
def was_ignored(self, code: str) -> Union[Selected, Ignored]:
|
||||||
# type: (str) -> Union[Selected, Ignored]
|
|
||||||
"""Determine if the code has been ignored by the user.
|
"""Determine if the code has been ignored by the user.
|
||||||
|
|
||||||
:param str code:
|
:param str code:
|
||||||
|
|
@ -219,8 +222,7 @@ class DecisionEngine(object):
|
||||||
|
|
||||||
return Selected.Implicitly
|
return Selected.Implicitly
|
||||||
|
|
||||||
def more_specific_decision_for(self, code):
|
def more_specific_decision_for(self, code: str) -> Decision:
|
||||||
# type: (str) -> Decision
|
|
||||||
select = find_first_match(code, self.all_selected)
|
select = find_first_match(code, self.all_selected)
|
||||||
extra_select = find_first_match(code, self.extended_selected)
|
extra_select = find_first_match(code, self.extended_selected)
|
||||||
ignore = find_first_match(code, self.ignored)
|
ignore = find_first_match(code, self.ignored)
|
||||||
|
|
@ -268,8 +270,7 @@ class DecisionEngine(object):
|
||||||
return Decision.Ignored
|
return Decision.Ignored
|
||||||
return Decision.Selected
|
return Decision.Selected
|
||||||
|
|
||||||
def make_decision(self, code):
|
def make_decision(self, code: str) -> Decision:
|
||||||
# type: (str) -> Decision
|
|
||||||
"""Decide if code should be ignored or selected."""
|
"""Decide if code should be ignored or selected."""
|
||||||
LOG.debug('Deciding if "%s" should be reported', code)
|
LOG.debug('Deciding if "%s" should be reported', code)
|
||||||
selected = self.was_selected(code)
|
selected = self.was_selected(code)
|
||||||
|
|
@ -295,8 +296,7 @@ class DecisionEngine(object):
|
||||||
decision = Decision.Ignored # pylint: disable=R0204
|
decision = Decision.Ignored # pylint: disable=R0204
|
||||||
return decision
|
return decision
|
||||||
|
|
||||||
def decision_for(self, code):
|
def decision_for(self, code: str) -> Decision:
|
||||||
# type: (str) -> Decision
|
|
||||||
"""Return the decision for a specific code.
|
"""Return the decision for a specific code.
|
||||||
|
|
||||||
This method caches the decisions for codes to avoid retracing the same
|
This method caches the decisions for codes to avoid retracing the same
|
||||||
|
|
@ -318,15 +318,15 @@ class DecisionEngine(object):
|
||||||
return decision
|
return decision
|
||||||
|
|
||||||
|
|
||||||
class StyleGuideManager(object):
|
class StyleGuideManager:
|
||||||
"""Manage multiple style guides for a single run."""
|
"""Manage multiple style guides for a single run."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
options, # type: argparse.Namespace
|
options: argparse.Namespace,
|
||||||
formatter, # type: base_formatter.BaseFormatter
|
formatter: base_formatter.BaseFormatter,
|
||||||
decider=None, # type: Optional[DecisionEngine]
|
decider: Optional[DecisionEngine] = None,
|
||||||
): # type: (...) -> None
|
) -> None:
|
||||||
"""Initialize our StyleGuide.
|
"""Initialize our StyleGuide.
|
||||||
|
|
||||||
.. todo:: Add parameter documentation.
|
.. todo:: Add parameter documentation.
|
||||||
|
|
@ -335,7 +335,7 @@ class StyleGuideManager(object):
|
||||||
self.formatter = formatter
|
self.formatter = formatter
|
||||||
self.stats = statistics.Statistics()
|
self.stats = statistics.Statistics()
|
||||||
self.decider = decider or DecisionEngine(options)
|
self.decider = decider or DecisionEngine(options)
|
||||||
self.style_guides = [] # type: List[StyleGuide]
|
self.style_guides: List[StyleGuide] = []
|
||||||
self.default_style_guide = StyleGuide(
|
self.default_style_guide = StyleGuide(
|
||||||
options, formatter, self.stats, decider=decider
|
options, formatter, self.stats, decider=decider
|
||||||
)
|
)
|
||||||
|
|
@ -346,8 +346,9 @@ class StyleGuideManager(object):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def populate_style_guides_with(self, options):
|
def populate_style_guides_with(
|
||||||
# type: (argparse.Namespace) -> Generator[StyleGuide, None, None]
|
self, options: argparse.Namespace
|
||||||
|
) -> Generator["StyleGuide", None, None]:
|
||||||
"""Generate style guides from the per-file-ignores option.
|
"""Generate style guides from the per-file-ignores option.
|
||||||
|
|
||||||
:param options:
|
:param options:
|
||||||
|
|
@ -367,8 +368,8 @@ class StyleGuideManager(object):
|
||||||
filename=filename, extend_ignore_with=violations
|
filename=filename, extend_ignore_with=violations
|
||||||
)
|
)
|
||||||
|
|
||||||
@lru_cache(maxsize=None)
|
@functools.lru_cache(maxsize=None)
|
||||||
def style_guide_for(self, filename): # type: (str) -> StyleGuide
|
def style_guide_for(self, filename: str) -> "StyleGuide":
|
||||||
"""Find the StyleGuide for the filename in particular."""
|
"""Find the StyleGuide for the filename in particular."""
|
||||||
guides = sorted(
|
guides = sorted(
|
||||||
(g for g in self.style_guides if g.applies_to(filename)),
|
(g for g in self.style_guides if g.applies_to(filename)),
|
||||||
|
|
@ -379,8 +380,9 @@ class StyleGuideManager(object):
|
||||||
return guides[0]
|
return guides[0]
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def processing_file(self, filename):
|
def processing_file(
|
||||||
# type: (str) -> Generator[StyleGuide, None, None]
|
self, filename: str
|
||||||
|
) -> Generator["StyleGuide", None, None]:
|
||||||
"""Record the fact that we're processing the file's results."""
|
"""Record the fact that we're processing the file's results."""
|
||||||
guide = self.style_guide_for(filename)
|
guide = self.style_guide_for(filename)
|
||||||
with guide.processing_file(filename):
|
with guide.processing_file(filename):
|
||||||
|
|
@ -388,14 +390,13 @@ class StyleGuideManager(object):
|
||||||
|
|
||||||
def handle_error(
|
def handle_error(
|
||||||
self,
|
self,
|
||||||
code,
|
code: str,
|
||||||
filename,
|
filename: str,
|
||||||
line_number,
|
line_number: int,
|
||||||
column_number,
|
column_number: Optional[int],
|
||||||
text,
|
text: str,
|
||||||
physical_line=None,
|
physical_line: Optional[str] = None,
|
||||||
):
|
) -> int:
|
||||||
# type: (str, str, int, Optional[int], str, Optional[str]) -> int
|
|
||||||
"""Handle an error reported by a check.
|
"""Handle an error reported by a check.
|
||||||
|
|
||||||
:param str code:
|
:param str code:
|
||||||
|
|
@ -423,8 +424,7 @@ class StyleGuideManager(object):
|
||||||
code, filename, line_number, column_number, text, physical_line
|
code, filename, line_number, column_number, text, physical_line
|
||||||
)
|
)
|
||||||
|
|
||||||
def add_diff_ranges(self, diffinfo):
|
def add_diff_ranges(self, diffinfo: Dict[str, Set[int]]) -> None:
|
||||||
# type: (Dict[str, Set[int]]) -> None
|
|
||||||
"""Update the StyleGuides to filter out information not in the diff.
|
"""Update the StyleGuides to filter out information not in the diff.
|
||||||
|
|
||||||
This provides information to the underlying StyleGuides so that only
|
This provides information to the underlying StyleGuides so that only
|
||||||
|
|
@ -437,16 +437,16 @@ class StyleGuideManager(object):
|
||||||
guide.add_diff_ranges(diffinfo)
|
guide.add_diff_ranges(diffinfo)
|
||||||
|
|
||||||
|
|
||||||
class StyleGuide(object):
|
class StyleGuide:
|
||||||
"""Manage a Flake8 user's style guide."""
|
"""Manage a Flake8 user's style guide."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
options, # type: argparse.Namespace
|
options: argparse.Namespace,
|
||||||
formatter, # type: base_formatter.BaseFormatter
|
formatter: base_formatter.BaseFormatter,
|
||||||
stats, # type: statistics.Statistics
|
stats: statistics.Statistics,
|
||||||
filename=None, # type: Optional[str]
|
filename: Optional[str] = None,
|
||||||
decider=None, # type: Optional[DecisionEngine]
|
decider: Optional[DecisionEngine] = None,
|
||||||
):
|
):
|
||||||
"""Initialize our StyleGuide.
|
"""Initialize our StyleGuide.
|
||||||
|
|
||||||
|
|
@ -459,14 +459,17 @@ class StyleGuide(object):
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
if self.filename:
|
if self.filename:
|
||||||
self.filename = utils.normalize_path(self.filename)
|
self.filename = utils.normalize_path(self.filename)
|
||||||
self._parsed_diff = {} # type: Dict[str, Set[int]]
|
self._parsed_diff: Dict[str, Set[int]] = {}
|
||||||
|
|
||||||
def __repr__(self): # type: () -> str
|
def __repr__(self) -> str:
|
||||||
"""Make it easier to debug which StyleGuide we're using."""
|
"""Make it easier to debug which StyleGuide we're using."""
|
||||||
return "<StyleGuide [{}]>".format(self.filename)
|
return f"<StyleGuide [{self.filename}]>"
|
||||||
|
|
||||||
def copy(self, filename=None, extend_ignore_with=None):
|
def copy(
|
||||||
# type: (Optional[str], Optional[Sequence[str]]) -> StyleGuide
|
self,
|
||||||
|
filename: Optional[str] = None,
|
||||||
|
extend_ignore_with: Optional[Sequence[str]] = None,
|
||||||
|
) -> "StyleGuide":
|
||||||
"""Create a copy of this style guide with different values."""
|
"""Create a copy of this style guide with different values."""
|
||||||
filename = filename or self.filename
|
filename = filename or self.filename
|
||||||
options = copy.deepcopy(self.options)
|
options = copy.deepcopy(self.options)
|
||||||
|
|
@ -476,14 +479,15 @@ class StyleGuide(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def processing_file(self, filename):
|
def processing_file(
|
||||||
# type: (str) -> Generator[StyleGuide, None, None]
|
self, filename: str
|
||||||
|
) -> Generator["StyleGuide", None, None]:
|
||||||
"""Record the fact that we're processing the file's results."""
|
"""Record the fact that we're processing the file's results."""
|
||||||
self.formatter.beginning(filename)
|
self.formatter.beginning(filename)
|
||||||
yield self
|
yield self
|
||||||
self.formatter.finished(filename)
|
self.formatter.finished(filename)
|
||||||
|
|
||||||
def applies_to(self, filename): # type: (str) -> bool
|
def applies_to(self, filename: str) -> bool:
|
||||||
"""Check if this StyleGuide applies to the file.
|
"""Check if this StyleGuide applies to the file.
|
||||||
|
|
||||||
:param str filename:
|
:param str filename:
|
||||||
|
|
@ -499,12 +503,11 @@ class StyleGuide(object):
|
||||||
return utils.matches_filename(
|
return utils.matches_filename(
|
||||||
filename,
|
filename,
|
||||||
patterns=[self.filename],
|
patterns=[self.filename],
|
||||||
log_message='{!r} does %(whether)smatch "%(path)s"'.format(self),
|
log_message=f'{self!r} does %(whether)smatch "%(path)s"',
|
||||||
logger=LOG,
|
logger=LOG,
|
||||||
)
|
)
|
||||||
|
|
||||||
def should_report_error(self, code):
|
def should_report_error(self, code: str) -> Decision:
|
||||||
# type: (str) -> Decision
|
|
||||||
"""Determine if the error code should be reported or ignored.
|
"""Determine if the error code should be reported or ignored.
|
||||||
|
|
||||||
This method only cares about the select and ignore rules as specified
|
This method only cares about the select and ignore rules as specified
|
||||||
|
|
@ -520,14 +523,13 @@ class StyleGuide(object):
|
||||||
|
|
||||||
def handle_error(
|
def handle_error(
|
||||||
self,
|
self,
|
||||||
code,
|
code: str,
|
||||||
filename,
|
filename: str,
|
||||||
line_number,
|
line_number: int,
|
||||||
column_number,
|
column_number: Optional[int],
|
||||||
text,
|
text: str,
|
||||||
physical_line=None,
|
physical_line: Optional[str] = None,
|
||||||
):
|
) -> int:
|
||||||
# type: (str, str, int, Optional[int], str, Optional[str]) -> int
|
|
||||||
"""Handle an error reported by a check.
|
"""Handle an error reported by a check.
|
||||||
|
|
||||||
:param str code:
|
:param str code:
|
||||||
|
|
@ -579,8 +581,7 @@ class StyleGuide(object):
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def add_diff_ranges(self, diffinfo):
|
def add_diff_ranges(self, diffinfo: Dict[str, Set[int]]) -> None:
|
||||||
# type: (Dict[str, Set[int]]) -> None
|
|
||||||
"""Update the StyleGuide to filter out information not in the diff.
|
"""Update the StyleGuide to filter out information not in the diff.
|
||||||
|
|
||||||
This provides information to the StyleGuide so that only the errors
|
This provides information to the StyleGuide so that only the errors
|
||||||
|
|
@ -592,14 +593,15 @@ class StyleGuide(object):
|
||||||
self._parsed_diff = diffinfo
|
self._parsed_diff = diffinfo
|
||||||
|
|
||||||
|
|
||||||
def find_more_specific(selected, ignored): # type: (str, str) -> Decision
|
def find_more_specific(selected: str, ignored: str) -> Decision:
|
||||||
if selected.startswith(ignored) and selected != ignored:
|
if selected.startswith(ignored) and selected != ignored:
|
||||||
return Decision.Selected
|
return Decision.Selected
|
||||||
return Decision.Ignored
|
return Decision.Ignored
|
||||||
|
|
||||||
|
|
||||||
def find_first_match(error_code, code_list):
|
def find_first_match(
|
||||||
# type: (str, Tuple[str, ...]) -> Optional[str]
|
error_code: str, code_list: Tuple[str, ...]
|
||||||
|
) -> Optional[str]:
|
||||||
startswith = error_code.startswith
|
startswith = error_code.startswith
|
||||||
for code in code_list:
|
for code in code_list:
|
||||||
if startswith(code):
|
if startswith(code):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"""Utility methods for flake8."""
|
"""Utility methods for flake8."""
|
||||||
import collections
|
import collections
|
||||||
import fnmatch as _fnmatch
|
import fnmatch as _fnmatch
|
||||||
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
|
|
@ -8,24 +9,33 @@ import os
|
||||||
import platform
|
import platform
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import textwrap
|
||||||
import tokenize
|
import tokenize
|
||||||
from typing import Callable, Dict, Generator, List, Optional, Pattern
|
from typing import Callable
|
||||||
from typing import Sequence, Set, Tuple, Union
|
from typing import Dict
|
||||||
|
from typing import Generator
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Pattern
|
||||||
|
from typing import Sequence
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from flake8 import exceptions
|
from flake8 import exceptions
|
||||||
from flake8._compat import lru_cache
|
|
||||||
|
|
||||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
if TYPE_CHECKING:
|
||||||
from flake8.plugins.manager import Plugin
|
from flake8.plugins.manager import Plugin
|
||||||
|
|
||||||
DIFF_HUNK_REGEXP = re.compile(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$")
|
DIFF_HUNK_REGEXP = re.compile(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$")
|
||||||
COMMA_SEPARATED_LIST_RE = re.compile(r"[,\s]")
|
COMMA_SEPARATED_LIST_RE = re.compile(r"[,\s]")
|
||||||
LOCAL_PLUGIN_LIST_RE = re.compile(r"[,\t\n\r\f\v]")
|
LOCAL_PLUGIN_LIST_RE = re.compile(r"[,\t\n\r\f\v]")
|
||||||
string_types = (str, type(u""))
|
|
||||||
|
|
||||||
|
|
||||||
def parse_comma_separated_list(value, regexp=COMMA_SEPARATED_LIST_RE):
|
def parse_comma_separated_list(
|
||||||
# type: (str, Pattern[str]) -> List[str]
|
value: str, regexp: Pattern[str] = COMMA_SEPARATED_LIST_RE
|
||||||
|
) -> List[str]:
|
||||||
"""Parse a comma-separated list.
|
"""Parse a comma-separated list.
|
||||||
|
|
||||||
:param value:
|
:param value:
|
||||||
|
|
@ -40,7 +50,7 @@ def parse_comma_separated_list(value, regexp=COMMA_SEPARATED_LIST_RE):
|
||||||
:rtype:
|
:rtype:
|
||||||
list
|
list
|
||||||
"""
|
"""
|
||||||
assert isinstance(value, string_types), value
|
assert isinstance(value, str), value
|
||||||
|
|
||||||
separated = regexp.split(value)
|
separated = regexp.split(value)
|
||||||
item_gen = (item.strip() for item in separated)
|
item_gen = (item.strip() for item in separated)
|
||||||
|
|
@ -59,8 +69,7 @@ _FILE_LIST_TOKEN_TYPES = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def _tokenize_files_to_codes_mapping(value):
|
def _tokenize_files_to_codes_mapping(value: str) -> List[_Token]:
|
||||||
# type: (str) -> List[_Token]
|
|
||||||
tokens = []
|
tokens = []
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(value):
|
while i < len(value):
|
||||||
|
|
@ -77,8 +86,9 @@ def _tokenize_files_to_codes_mapping(value):
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
def parse_files_to_codes_mapping(value_): # noqa: C901
|
def parse_files_to_codes_mapping( # noqa: C901
|
||||||
# type: (Union[Sequence[str], str]) -> List[Tuple[str, List[str]]]
|
value_: Union[Sequence[str], str]
|
||||||
|
) -> List[Tuple[str, List[str]]]:
|
||||||
"""Parse a files-to-codes mapping.
|
"""Parse a files-to-codes mapping.
|
||||||
|
|
||||||
A files-to-codes mapping a sequence of values specified as
|
A files-to-codes mapping a sequence of values specified as
|
||||||
|
|
@ -88,22 +98,22 @@ def parse_files_to_codes_mapping(value_): # noqa: C901
|
||||||
:param value: String to be parsed and normalized.
|
:param value: String to be parsed and normalized.
|
||||||
:type value: str
|
:type value: str
|
||||||
"""
|
"""
|
||||||
if not isinstance(value_, string_types):
|
if not isinstance(value_, str):
|
||||||
value = "\n".join(value_)
|
value = "\n".join(value_)
|
||||||
else:
|
else:
|
||||||
value = value_
|
value = value_
|
||||||
|
|
||||||
ret = [] # type: List[Tuple[str, List[str]]]
|
ret: List[Tuple[str, List[str]]] = []
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
class State:
|
class State:
|
||||||
seen_sep = True
|
seen_sep = True
|
||||||
seen_colon = False
|
seen_colon = False
|
||||||
filenames = [] # type: List[str]
|
filenames: List[str] = []
|
||||||
codes = [] # type: List[str]
|
codes: List[str] = []
|
||||||
|
|
||||||
def _reset(): # type: () -> None
|
def _reset() -> None:
|
||||||
if State.codes:
|
if State.codes:
|
||||||
for filename in State.filenames:
|
for filename in State.filenames:
|
||||||
ret.append((filename, State.codes))
|
ret.append((filename, State.codes))
|
||||||
|
|
@ -112,16 +122,12 @@ def parse_files_to_codes_mapping(value_): # noqa: C901
|
||||||
State.filenames = []
|
State.filenames = []
|
||||||
State.codes = []
|
State.codes = []
|
||||||
|
|
||||||
def _unexpected_token(): # type: () -> exceptions.ExecutionError
|
def _unexpected_token() -> exceptions.ExecutionError:
|
||||||
def _indent(s): # type: (str) -> str
|
|
||||||
return " " + s.strip().replace("\n", "\n ")
|
|
||||||
|
|
||||||
return exceptions.ExecutionError(
|
return exceptions.ExecutionError(
|
||||||
"Expected `per-file-ignores` to be a mapping from file exclude "
|
f"Expected `per-file-ignores` to be a mapping from file exclude "
|
||||||
"patterns to ignore codes.\n\n"
|
f"patterns to ignore codes.\n\n"
|
||||||
"Configured `per-file-ignores` setting:\n\n{}".format(
|
f"Configured `per-file-ignores` setting:\n\n"
|
||||||
_indent(value)
|
f"{textwrap.indent(value.strip(), ' ')}"
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for token in _tokenize_files_to_codes_mapping(value):
|
for token in _tokenize_files_to_codes_mapping(value):
|
||||||
|
|
@ -155,8 +161,9 @@ def parse_files_to_codes_mapping(value_): # noqa: C901
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def normalize_paths(paths, parent=os.curdir):
|
def normalize_paths(
|
||||||
# type: (Sequence[str], str) -> List[str]
|
paths: Sequence[str], parent: str = os.curdir
|
||||||
|
) -> List[str]:
|
||||||
"""Normalize a list of paths relative to a parent directory.
|
"""Normalize a list of paths relative to a parent directory.
|
||||||
|
|
||||||
:returns:
|
:returns:
|
||||||
|
|
@ -168,8 +175,7 @@ def normalize_paths(paths, parent=os.curdir):
|
||||||
return [normalize_path(p, parent) for p in paths]
|
return [normalize_path(p, parent) for p in paths]
|
||||||
|
|
||||||
|
|
||||||
def normalize_path(path, parent=os.curdir):
|
def normalize_path(path: str, parent: str = os.curdir) -> str:
|
||||||
# type: (str, str) -> str
|
|
||||||
"""Normalize a single-path.
|
"""Normalize a single-path.
|
||||||
|
|
||||||
:returns:
|
:returns:
|
||||||
|
|
@ -190,7 +196,9 @@ def normalize_path(path, parent=os.curdir):
|
||||||
return path.rstrip(separator + alternate_separator)
|
return path.rstrip(separator + alternate_separator)
|
||||||
|
|
||||||
|
|
||||||
def _stdin_get_value_py3(): # type: () -> str
|
@functools.lru_cache(maxsize=1)
|
||||||
|
def stdin_get_value() -> str:
|
||||||
|
"""Get and cache it so plugins can use it."""
|
||||||
stdin_value = sys.stdin.buffer.read()
|
stdin_value = sys.stdin.buffer.read()
|
||||||
fd = io.BytesIO(stdin_value)
|
fd = io.BytesIO(stdin_value)
|
||||||
try:
|
try:
|
||||||
|
|
@ -201,25 +209,12 @@ def _stdin_get_value_py3(): # type: () -> str
|
||||||
return stdin_value.decode("utf-8")
|
return stdin_value.decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=1)
|
def stdin_get_lines() -> List[str]:
|
||||||
def stdin_get_value(): # type: () -> str
|
|
||||||
"""Get and cache it so plugins can use it."""
|
|
||||||
if sys.version_info < (3,):
|
|
||||||
return sys.stdin.read()
|
|
||||||
else:
|
|
||||||
return _stdin_get_value_py3()
|
|
||||||
|
|
||||||
|
|
||||||
def stdin_get_lines(): # type: () -> List[str]
|
|
||||||
"""Return lines of stdin split according to file splitting."""
|
"""Return lines of stdin split according to file splitting."""
|
||||||
if sys.version_info < (3,):
|
return list(io.StringIO(stdin_get_value()))
|
||||||
return list(io.BytesIO(stdin_get_value()))
|
|
||||||
else:
|
|
||||||
return list(io.StringIO(stdin_get_value()))
|
|
||||||
|
|
||||||
|
|
||||||
def parse_unified_diff(diff=None):
|
def parse_unified_diff(diff: Optional[str] = None) -> Dict[str, Set[int]]:
|
||||||
# type: (Optional[str]) -> Dict[str, Set[int]]
|
|
||||||
"""Parse the unified diff passed on stdin.
|
"""Parse the unified diff passed on stdin.
|
||||||
|
|
||||||
:returns:
|
:returns:
|
||||||
|
|
@ -233,7 +228,7 @@ def parse_unified_diff(diff=None):
|
||||||
|
|
||||||
number_of_rows = None
|
number_of_rows = None
|
||||||
current_path = None
|
current_path = None
|
||||||
parsed_paths = collections.defaultdict(set) # type: Dict[str, Set[int]]
|
parsed_paths: Dict[str, Set[int]] = collections.defaultdict(set)
|
||||||
for line in diff.splitlines():
|
for line in diff.splitlines():
|
||||||
if number_of_rows:
|
if number_of_rows:
|
||||||
# NOTE(sigmavirus24): Below we use a slice because stdin may be
|
# NOTE(sigmavirus24): Below we use a slice because stdin may be
|
||||||
|
|
@ -291,8 +286,7 @@ def parse_unified_diff(diff=None):
|
||||||
return parsed_paths
|
return parsed_paths
|
||||||
|
|
||||||
|
|
||||||
def is_windows():
|
def is_windows() -> bool:
|
||||||
# type: () -> bool
|
|
||||||
"""Determine if we're running on Windows.
|
"""Determine if we're running on Windows.
|
||||||
|
|
||||||
:returns:
|
:returns:
|
||||||
|
|
@ -303,8 +297,7 @@ def is_windows():
|
||||||
return os.name == "nt"
|
return os.name == "nt"
|
||||||
|
|
||||||
|
|
||||||
def is_using_stdin(paths):
|
def is_using_stdin(paths: List[str]) -> bool:
|
||||||
# type: (List[str]) -> bool
|
|
||||||
"""Determine if we're going to read from stdin.
|
"""Determine if we're going to read from stdin.
|
||||||
|
|
||||||
:param list paths:
|
:param list paths:
|
||||||
|
|
@ -317,12 +310,14 @@ def is_using_stdin(paths):
|
||||||
return "-" in paths
|
return "-" in paths
|
||||||
|
|
||||||
|
|
||||||
def _default_predicate(*args): # type: (*str) -> bool
|
def _default_predicate(*args: str) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def filenames_from(arg, predicate=None):
|
def filenames_from(
|
||||||
# type: (str, Optional[Callable[[str], bool]]) -> Generator[str, None, None] # noqa: E501
|
arg: str, predicate: Optional[Callable[[str], bool]] = None
|
||||||
|
) -> Generator[str, None, None]:
|
||||||
|
# noqa: E501
|
||||||
"""Generate filenames from an argument.
|
"""Generate filenames from an argument.
|
||||||
|
|
||||||
:param str arg:
|
:param str arg:
|
||||||
|
|
@ -362,8 +357,7 @@ def filenames_from(arg, predicate=None):
|
||||||
yield arg
|
yield arg
|
||||||
|
|
||||||
|
|
||||||
def fnmatch(filename, patterns):
|
def fnmatch(filename: str, patterns: Sequence[str]) -> bool:
|
||||||
# type: (str, Sequence[str]) -> bool
|
|
||||||
"""Wrap :func:`fnmatch.fnmatch` to add some functionality.
|
"""Wrap :func:`fnmatch.fnmatch` to add some functionality.
|
||||||
|
|
||||||
:param str filename:
|
:param str filename:
|
||||||
|
|
@ -381,8 +375,7 @@ def fnmatch(filename, patterns):
|
||||||
return any(_fnmatch.fnmatch(filename, pattern) for pattern in patterns)
|
return any(_fnmatch.fnmatch(filename, pattern) for pattern in patterns)
|
||||||
|
|
||||||
|
|
||||||
def parameters_for(plugin):
|
def parameters_for(plugin: "Plugin") -> Dict[str, bool]:
|
||||||
# type: (Plugin) -> Dict[str, bool]
|
|
||||||
"""Return the parameters for the plugin.
|
"""Return the parameters for the plugin.
|
||||||
|
|
||||||
This will inspect the plugin and return either the function parameters
|
This will inspect the plugin and return either the function parameters
|
||||||
|
|
@ -404,24 +397,11 @@ def parameters_for(plugin):
|
||||||
if is_class: # The plugin is a class
|
if is_class: # The plugin is a class
|
||||||
func = plugin.plugin.__init__
|
func = plugin.plugin.__init__
|
||||||
|
|
||||||
if sys.version_info < (3, 3):
|
parameters = {
|
||||||
argspec = inspect.getargspec(func)
|
parameter.name: parameter.default is parameter.empty
|
||||||
start_of_optional_args = len(argspec[0]) - len(argspec[-1] or [])
|
for parameter in inspect.signature(func).parameters.values()
|
||||||
parameter_names = argspec[0]
|
if parameter.kind == parameter.POSITIONAL_OR_KEYWORD
|
||||||
parameters = collections.OrderedDict(
|
}
|
||||||
[
|
|
||||||
(name, position < start_of_optional_args)
|
|
||||||
for position, name in enumerate(parameter_names)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
parameters = collections.OrderedDict(
|
|
||||||
[
|
|
||||||
(parameter.name, parameter.default is parameter.empty)
|
|
||||||
for parameter in inspect.signature(func).parameters.values()
|
|
||||||
if parameter.kind == parameter.POSITIONAL_OR_KEYWORD
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
if is_class:
|
if is_class:
|
||||||
parameters.pop("self", None)
|
parameters.pop("self", None)
|
||||||
|
|
@ -429,8 +409,12 @@ def parameters_for(plugin):
|
||||||
return parameters
|
return parameters
|
||||||
|
|
||||||
|
|
||||||
def matches_filename(path, patterns, log_message, logger):
|
def matches_filename(
|
||||||
# type: (str, Sequence[str], str, logging.Logger) -> bool
|
path: str,
|
||||||
|
patterns: Sequence[str],
|
||||||
|
log_message: str,
|
||||||
|
logger: logging.Logger,
|
||||||
|
) -> bool:
|
||||||
"""Use fnmatch to discern if a path exists in patterns.
|
"""Use fnmatch to discern if a path exists in patterns.
|
||||||
|
|
||||||
:param str path:
|
:param str path:
|
||||||
|
|
@ -462,7 +446,7 @@ def matches_filename(path, patterns, log_message, logger):
|
||||||
return match
|
return match
|
||||||
|
|
||||||
|
|
||||||
def get_python_version(): # type: () -> str
|
def get_python_version() -> str:
|
||||||
"""Find and format the python implementation and version.
|
"""Find and format the python implementation and version.
|
||||||
|
|
||||||
:returns:
|
:returns:
|
||||||
|
|
@ -470,7 +454,7 @@ def get_python_version(): # type: () -> str
|
||||||
:rtype:
|
:rtype:
|
||||||
str
|
str
|
||||||
"""
|
"""
|
||||||
return "%s %s on %s" % (
|
return "{} {} on {}".format(
|
||||||
platform.python_implementation(),
|
platform.python_implementation(),
|
||||||
platform.python_version(),
|
platform.python_version(),
|
||||||
platform.system(),
|
platform.system(),
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
from some.module.that.has.nested.sub.modules import ClassWithVeryVeryVeryVeryLongName # noqa: E501,F401
|
from some.module.that.has.nested.sub.modules import \
|
||||||
|
ClassWithVeryVeryVeryVeryLongName # noqa: E501,F401
|
||||||
|
|
||||||
# ClassWithVeryVeryVeryVeryLongName()
|
# ClassWithVeryVeryVeryVeryLongName()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""Module that is off sys.path by default, for testing local-plugin-paths."""
|
"""Module that is off sys.path by default, for testing local-plugin-paths."""
|
||||||
|
|
||||||
|
|
||||||
class ExtensionTestPlugin2(object):
|
class ExtensionTestPlugin2:
|
||||||
"""Extension test plugin in its own directory."""
|
"""Extension test plugin in its own directory."""
|
||||||
|
|
||||||
name = 'ExtensionTestPlugin2'
|
name = 'ExtensionTestPlugin2'
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"""Integration tests for the checker submodule."""
|
"""Integration tests for the checker submodule."""
|
||||||
import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import checker
|
from flake8 import checker
|
||||||
|
|
@ -20,7 +21,7 @@ EXPECTED_RESULT_PHYSICAL_LINE = (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PluginClass(object):
|
class PluginClass:
|
||||||
"""Simple file plugin class yielding the expected report."""
|
"""Simple file plugin class yielding the expected report."""
|
||||||
|
|
||||||
name = 'test'
|
name = 'test'
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
"""Integration tests for the main entrypoint of flake8."""
|
"""Integration tests for the main entrypoint of flake8."""
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
|
|
@ -280,13 +280,13 @@ def test_obtaining_args_from_sys_argv_when_not_explicity_provided(capsys):
|
||||||
def test_cli_config_option_respected(tmp_path):
|
def test_cli_config_option_respected(tmp_path):
|
||||||
"""Test --config is used."""
|
"""Test --config is used."""
|
||||||
config = tmp_path / "flake8.ini"
|
config = tmp_path / "flake8.ini"
|
||||||
config.write_text(u"""\
|
config.write_text("""\
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore = F401
|
ignore = F401
|
||||||
""")
|
""")
|
||||||
|
|
||||||
py_file = tmp_path / "t.py"
|
py_file = tmp_path / "t.py"
|
||||||
py_file.write_text(u"import os\n")
|
py_file.write_text("import os\n")
|
||||||
|
|
||||||
_call_main(["--config", str(config), str(py_file)])
|
_call_main(["--config", str(config), str(py_file)])
|
||||||
|
|
||||||
|
|
@ -294,13 +294,13 @@ ignore = F401
|
||||||
def test_cli_isolated_overrides_config_option(tmp_path):
|
def test_cli_isolated_overrides_config_option(tmp_path):
|
||||||
"""Test --isolated overrides --config."""
|
"""Test --isolated overrides --config."""
|
||||||
config = tmp_path / "flake8.ini"
|
config = tmp_path / "flake8.ini"
|
||||||
config.write_text(u"""\
|
config.write_text("""\
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore = F401
|
ignore = F401
|
||||||
""")
|
""")
|
||||||
|
|
||||||
py_file = tmp_path / "t.py"
|
py_file = tmp_path / "t.py"
|
||||||
py_file.write_text(u"import os\n")
|
py_file.write_text("import os\n")
|
||||||
|
|
||||||
_call_main(["--isolated", "--config", str(config), str(py_file)], retv=1)
|
_call_main(["--isolated", "--config", str(config), str(py_file)], retv=1)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
"""Integration tests for plugin loading."""
|
"""Integration tests for plugin loading."""
|
||||||
from flake8.main import application
|
from flake8.main import application
|
||||||
|
|
||||||
|
|
||||||
LOCAL_PLUGIN_CONFIG = 'tests/fixtures/config_files/local-plugin.ini'
|
LOCAL_PLUGIN_CONFIG = 'tests/fixtures/config_files/local-plugin.ini'
|
||||||
LOCAL_PLUGIN_PATH_CONFIG = 'tests/fixtures/config_files/local-plugin-path.ini'
|
LOCAL_PLUGIN_PATH_CONFIG = 'tests/fixtures/config_files/local-plugin-path.ini'
|
||||||
|
|
||||||
|
|
||||||
class ExtensionTestPlugin(object):
|
class ExtensionTestPlugin:
|
||||||
"""Extension test plugin."""
|
"""Extension test plugin."""
|
||||||
|
|
||||||
name = 'ExtensionTestPlugin'
|
name = 'ExtensionTestPlugin'
|
||||||
|
|
@ -24,7 +23,7 @@ class ExtensionTestPlugin(object):
|
||||||
parser.add_option('--anopt')
|
parser.add_option('--anopt')
|
||||||
|
|
||||||
|
|
||||||
class ReportTestPlugin(object):
|
class ReportTestPlugin:
|
||||||
"""Report test plugin."""
|
"""Report test plugin."""
|
||||||
|
|
||||||
name = 'ReportTestPlugin'
|
name = 'ReportTestPlugin'
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
"""Tests for the Application class."""
|
"""Tests for the Application class."""
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8.main import application as app
|
from flake8.main import application as app
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""Tests for the BaseFormatter object."""
|
"""Tests for the BaseFormatter object."""
|
||||||
import argparse
|
import argparse
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import style_guide
|
from flake8 import style_guide
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""Tests for the Manager object for FileCheckers."""
|
"""Tests for the Manager object for FileCheckers."""
|
||||||
import errno
|
import errno
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import checker
|
from flake8 import checker
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""Tests for the ConfigFileFinder."""
|
"""Tests for the ConfigFileFinder."""
|
||||||
import configparser
|
import configparser
|
||||||
import os
|
import os
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8.options import config
|
from flake8.options import config
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"""Tests for our debugging module."""
|
"""Tests for our debugging module."""
|
||||||
import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8.main import debug
|
from flake8.main import debug
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"""Unit tests for the FileChecker class."""
|
"""Unit tests for the FileChecker class."""
|
||||||
import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import flake8
|
import flake8
|
||||||
|
|
@ -50,7 +51,7 @@ def test_nonexistent_file():
|
||||||
def test_raises_exception_on_failed_plugin(tmp_path, default_options):
|
def test_raises_exception_on_failed_plugin(tmp_path, default_options):
|
||||||
"""Checks that a failing plugin results in PluginExecutionFailed."""
|
"""Checks that a failing plugin results in PluginExecutionFailed."""
|
||||||
foobar = tmp_path / 'foobar.py'
|
foobar = tmp_path / 'foobar.py'
|
||||||
foobar.write_text(u"I exist!") # Create temp file
|
foobar.write_text("I exist!") # Create temp file
|
||||||
plugin = {
|
plugin = {
|
||||||
"name": "failure",
|
"name": "failure",
|
||||||
"plugin_name": "failure", # Both are necessary
|
"plugin_name": "failure", # Both are necessary
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
"""Tests for the FileProcessor class."""
|
"""Tests for the FileProcessor class."""
|
||||||
import ast
|
import ast
|
||||||
import tokenize
|
import tokenize
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import processor
|
from flake8 import processor
|
||||||
|
|
@ -46,7 +46,7 @@ def test_read_lines_unknown_encoding(tmpdir, default_options):
|
||||||
|
|
||||||
@pytest.mark.parametrize('first_line', [
|
@pytest.mark.parametrize('first_line', [
|
||||||
'\xEF\xBB\xBF"""Module docstring."""\n',
|
'\xEF\xBB\xBF"""Module docstring."""\n',
|
||||||
u'\uFEFF"""Module docstring."""\n',
|
'\uFEFF"""Module docstring."""\n',
|
||||||
])
|
])
|
||||||
def test_strip_utf_bom(first_line, default_options):
|
def test_strip_utf_bom(first_line, default_options):
|
||||||
r"""Verify that we strip '\xEF\xBB\xBF' from the first line."""
|
r"""Verify that we strip '\xEF\xBB\xBF' from the first line."""
|
||||||
|
|
@ -58,7 +58,7 @@ def test_strip_utf_bom(first_line, default_options):
|
||||||
|
|
||||||
@pytest.mark.parametrize('lines, expected', [
|
@pytest.mark.parametrize('lines, expected', [
|
||||||
(['\xEF\xBB\xBF"""Module docstring."""\n'], False),
|
(['\xEF\xBB\xBF"""Module docstring."""\n'], False),
|
||||||
([u'\uFEFF"""Module docstring."""\n'], False),
|
(['\uFEFF"""Module docstring."""\n'], False),
|
||||||
(['#!/usr/bin/python', '# flake8 is great', 'a = 1'], False),
|
(['#!/usr/bin/python', '# flake8 is great', 'a = 1'], False),
|
||||||
(['#!/usr/bin/python', '# flake8: noqa', 'a = 1'], True),
|
(['#!/usr/bin/python', '# flake8: noqa', 'a = 1'], True),
|
||||||
(['#!/usr/bin/python', '# flake8:noqa', 'a = 1'], True),
|
(['#!/usr/bin/python', '# flake8:noqa', 'a = 1'], True),
|
||||||
|
|
@ -130,7 +130,7 @@ def test_noqa_line_for(default_options):
|
||||||
])
|
])
|
||||||
|
|
||||||
for i in range(1, 4):
|
for i in range(1, 4):
|
||||||
assert file_processor.noqa_line_for(i) == 'Line {0}\n'.format(i)
|
assert file_processor.noqa_line_for(i) == f'Line {i}\n'
|
||||||
|
|
||||||
|
|
||||||
def test_noqa_line_for_continuation(default_options):
|
def test_noqa_line_for_continuation(default_options):
|
||||||
|
|
@ -182,7 +182,7 @@ def test_next_line(default_options):
|
||||||
])
|
])
|
||||||
|
|
||||||
for i in range(1, 4):
|
for i in range(1, 4):
|
||||||
assert file_processor.next_line() == 'Line {}'.format(i)
|
assert file_processor.next_line() == f'Line {i}'
|
||||||
assert file_processor.line_number == i
|
assert file_processor.line_number == i
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
"""Tests for get_local_plugins."""
|
"""Tests for get_local_plugins."""
|
||||||
import mock
|
from unittest import mock
|
||||||
|
|
||||||
from flake8.options import config
|
from flake8.options import config
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
"""Tests for Flake8's legacy API."""
|
"""Tests for Flake8's legacy API."""
|
||||||
import argparse
|
import argparse
|
||||||
import os.path
|
import os.path
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8.api import legacy as api
|
from flake8.api import legacy as api
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""Unit tests for flake8.options.config.MergedConfigParser."""
|
"""Unit tests for flake8.options.config.MergedConfigParser."""
|
||||||
import os
|
import os
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8.options import config
|
from flake8.options import config
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""Unit tests for flake8.options.manager.Option."""
|
"""Unit tests for flake8.options.manager.Option."""
|
||||||
import functools
|
import functools
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8.options import manager
|
from flake8.options import manager
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
"""Unit tests for flake.options.manager.OptionManager."""
|
"""Unit tests for flake.options.manager.OptionManager."""
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""Tests for flake8.plugins.manager.Plugin."""
|
"""Tests for flake8.plugins.manager.Plugin."""
|
||||||
import argparse
|
import argparse
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import exceptions
|
from flake8 import exceptions
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
"""Tests for flake8.plugins.manager.PluginManager."""
|
"""Tests for flake8.plugins.manager.PluginManager."""
|
||||||
import mock
|
from unittest import mock
|
||||||
|
|
||||||
from flake8._compat import importlib_metadata
|
from flake8._compat import importlib_metadata
|
||||||
from flake8.plugins import manager
|
from flake8.plugins import manager
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"""Tests for flake8.plugins.manager.PluginTypeManager."""
|
"""Tests for flake8.plugins.manager.PluginTypeManager."""
|
||||||
import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import exceptions
|
from flake8 import exceptions
|
||||||
|
|
|
||||||
|
|
@ -111,8 +111,8 @@ def test_statistic_for_retrieves_more_than_one_value():
|
||||||
"""Show this works for more than a couple statistic values."""
|
"""Show this works for more than a couple statistic values."""
|
||||||
aggregator = stats.Statistics()
|
aggregator = stats.Statistics()
|
||||||
for i in range(50):
|
for i in range(50):
|
||||||
aggregator.record(make_error(code='E1{:02d}'.format(i)))
|
aggregator.record(make_error(code=f'E1{i:02d}'))
|
||||||
aggregator.record(make_error(code='W2{:02d}'.format(i)))
|
aggregator.record(make_error(code=f'W2{i:02d}'))
|
||||||
|
|
||||||
statistics = list(aggregator.statistics_for('E'))
|
statistics = list(aggregator.statistics_for('E'))
|
||||||
assert len(statistics) == 50
|
assert len(statistics) == 50
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""Tests for the flake8.style_guide.StyleGuide class."""
|
"""Tests for the flake8.style_guide.StyleGuide class."""
|
||||||
import argparse
|
import argparse
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import statistics
|
from flake8 import statistics
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ import io
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import exceptions
|
from flake8 import exceptions
|
||||||
|
|
@ -134,7 +134,7 @@ def test_normalize_path(value, expected):
|
||||||
(["flake8", "pep8", "pyflakes", "mccabe"],
|
(["flake8", "pep8", "pyflakes", "mccabe"],
|
||||||
["flake8", "pep8", "pyflakes", "mccabe"]),
|
["flake8", "pep8", "pyflakes", "mccabe"]),
|
||||||
(["../flake8", "../pep8", "../pyflakes", "../mccabe"],
|
(["../flake8", "../pep8", "../pyflakes", "../mccabe"],
|
||||||
[os.path.abspath("../" + p) for p in RELATIVE_PATHS]),
|
[os.path.abspath(f"../{p}") for p in RELATIVE_PATHS]),
|
||||||
])
|
])
|
||||||
def test_normalize_paths(value, expected):
|
def test_normalize_paths(value, expected):
|
||||||
"""Verify we normalizes a sequence of paths provided to the tool."""
|
"""Verify we normalizes a sequence of paths provided to the tool."""
|
||||||
|
|
@ -242,7 +242,7 @@ def test_filenames_from_exclude_doesnt_exclude_directory_names(tmpdir):
|
||||||
|
|
||||||
def test_parameters_for_class_plugin():
|
def test_parameters_for_class_plugin():
|
||||||
"""Verify that we can retrieve the parameters for a class plugin."""
|
"""Verify that we can retrieve the parameters for a class plugin."""
|
||||||
class FakeCheck(object):
|
class FakeCheck:
|
||||||
def __init__(self, tree):
|
def __init__(self, tree):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
@ -268,7 +268,7 @@ def test_parameters_for_function_plugin():
|
||||||
|
|
||||||
def read_diff_file(filename):
|
def read_diff_file(filename):
|
||||||
"""Read the diff file in its entirety."""
|
"""Read the diff file in its entirety."""
|
||||||
with open(filename, 'r') as fd:
|
with open(filename) as fd:
|
||||||
content = fd.read()
|
content = fd.read()
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
@ -308,7 +308,6 @@ def test_matches_filename_for_excluding_dotfiles():
|
||||||
assert not utils.matches_filename('..', ('.*',), '', logger)
|
assert not utils.matches_filename('..', ('.*',), '', logger)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail(sys.version_info < (3,), reason='py3+ only behaviour')
|
|
||||||
def test_stdin_get_value_crlf():
|
def test_stdin_get_value_crlf():
|
||||||
"""Ensure that stdin is normalized from crlf to lf."""
|
"""Ensure that stdin is normalized from crlf to lf."""
|
||||||
stdin = io.TextIOWrapper(io.BytesIO(b'1\r\n2\r\n'), 'UTF-8')
|
stdin = io.TextIOWrapper(io.BytesIO(b'1\r\n2\r\n'), 'UTF-8')
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"""Tests for the flake8.style_guide.Violation class."""
|
"""Tests for the flake8.style_guide.Violation class."""
|
||||||
import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import style_guide
|
from flake8 import style_guide
|
||||||
|
|
|
||||||
23
tox.ini
23
tox.ini
|
|
@ -1,10 +1,9 @@
|
||||||
[tox]
|
[tox]
|
||||||
minversion=2.3.1
|
minversion=2.3.1
|
||||||
envlist = py27,py35,py36,py37,py38,flake8,linters,docs
|
envlist = py36,py37,py38,flake8,linters,docs
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
deps =
|
deps =
|
||||||
mock>=2.0.0
|
|
||||||
pytest!=3.0.5,!=5.2.3
|
pytest!=3.0.5,!=5.2.3
|
||||||
coverage
|
coverage
|
||||||
commands =
|
commands =
|
||||||
|
|
@ -14,14 +13,8 @@ commands =
|
||||||
# ensure 100% coverage of tests
|
# ensure 100% coverage of tests
|
||||||
coverage report --fail-under 100 --include tests/*
|
coverage report --fail-under 100 --include tests/*
|
||||||
|
|
||||||
[testenv:venv]
|
|
||||||
deps =
|
|
||||||
.
|
|
||||||
commands = {posargs}
|
|
||||||
|
|
||||||
# Dogfood our current master version
|
# Dogfood our current master version
|
||||||
[testenv:dogfood]
|
[testenv:dogfood]
|
||||||
basepython = python3
|
|
||||||
skip_install = true
|
skip_install = true
|
||||||
deps =
|
deps =
|
||||||
wheel
|
wheel
|
||||||
|
|
@ -33,20 +26,17 @@ commands =
|
||||||
|
|
||||||
# Linters
|
# Linters
|
||||||
[testenv:flake8]
|
[testenv:flake8]
|
||||||
basepython = python3
|
|
||||||
skip_install = true
|
skip_install = true
|
||||||
deps =
|
deps =
|
||||||
flake8
|
flake8
|
||||||
flake8-bugbear
|
flake8-bugbear
|
||||||
flake8-docstrings>=1.3.1
|
flake8-docstrings>=1.3.1
|
||||||
flake8-import-order>=0.9
|
|
||||||
flake8-typing-imports>=1.1
|
flake8-typing-imports>=1.1
|
||||||
pep8-naming
|
pep8-naming
|
||||||
commands =
|
commands =
|
||||||
flake8 src/flake8/ tests/ setup.py
|
flake8 src/flake8/ tests/ setup.py
|
||||||
|
|
||||||
[testenv:pylint]
|
[testenv:pylint]
|
||||||
basepython = python3
|
|
||||||
skip_install = true
|
skip_install = true
|
||||||
deps =
|
deps =
|
||||||
pyflakes
|
pyflakes
|
||||||
|
|
@ -55,7 +45,6 @@ commands =
|
||||||
pylint src/flake8
|
pylint src/flake8
|
||||||
|
|
||||||
[testenv:doc8]
|
[testenv:doc8]
|
||||||
basepython = python3
|
|
||||||
skip_install = true
|
skip_install = true
|
||||||
deps =
|
deps =
|
||||||
sphinx
|
sphinx
|
||||||
|
|
@ -64,14 +53,12 @@ commands =
|
||||||
doc8 docs/source/
|
doc8 docs/source/
|
||||||
|
|
||||||
[testenv:pre-commit]
|
[testenv:pre-commit]
|
||||||
basepython = python3
|
|
||||||
skip_install = true
|
skip_install = true
|
||||||
deps = pre-commit
|
deps = pre-commit
|
||||||
commands =
|
commands =
|
||||||
pre-commit run --all-files --show-diff-on-failure
|
pre-commit run --all-files --show-diff-on-failure
|
||||||
|
|
||||||
[testenv:bandit]
|
[testenv:bandit]
|
||||||
basepython = python3
|
|
||||||
skip_install = true
|
skip_install = true
|
||||||
deps =
|
deps =
|
||||||
bandit
|
bandit
|
||||||
|
|
@ -79,7 +66,6 @@ commands =
|
||||||
bandit -r src/flake8/ -c .bandit.yml
|
bandit -r src/flake8/ -c .bandit.yml
|
||||||
|
|
||||||
[testenv:linters]
|
[testenv:linters]
|
||||||
basepython = python3
|
|
||||||
skip_install = true
|
skip_install = true
|
||||||
deps =
|
deps =
|
||||||
{[testenv:flake8]deps}
|
{[testenv:flake8]deps}
|
||||||
|
|
@ -96,7 +82,6 @@ commands =
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
[testenv:docs]
|
[testenv:docs]
|
||||||
basepython = python3
|
|
||||||
deps =
|
deps =
|
||||||
-rdocs/source/requirements.txt
|
-rdocs/source/requirements.txt
|
||||||
commands =
|
commands =
|
||||||
|
|
@ -104,7 +89,6 @@ commands =
|
||||||
sphinx-build -E -W -c docs/source/ -b man docs/source/ docs/build/man
|
sphinx-build -E -W -c docs/source/ -b man docs/source/ docs/build/man
|
||||||
|
|
||||||
[testenv:serve-docs]
|
[testenv:serve-docs]
|
||||||
basepython = python3
|
|
||||||
skip_install = true
|
skip_install = true
|
||||||
changedir = docs/build/html
|
changedir = docs/build/html
|
||||||
deps =
|
deps =
|
||||||
|
|
@ -112,7 +96,6 @@ commands =
|
||||||
python -m http.server {posargs}
|
python -m http.server {posargs}
|
||||||
|
|
||||||
[testenv:readme]
|
[testenv:readme]
|
||||||
basepython = python3
|
|
||||||
deps =
|
deps =
|
||||||
readme_renderer
|
readme_renderer
|
||||||
commands =
|
commands =
|
||||||
|
|
@ -120,7 +103,6 @@ commands =
|
||||||
|
|
||||||
# Release tooling
|
# Release tooling
|
||||||
[testenv:build]
|
[testenv:build]
|
||||||
basepython = python3
|
|
||||||
skip_install = true
|
skip_install = true
|
||||||
deps =
|
deps =
|
||||||
wheel
|
wheel
|
||||||
|
|
@ -129,7 +111,6 @@ commands =
|
||||||
python setup.py -q sdist bdist_wheel
|
python setup.py -q sdist bdist_wheel
|
||||||
|
|
||||||
[testenv:release]
|
[testenv:release]
|
||||||
basepython = python3
|
|
||||||
skip_install = true
|
skip_install = true
|
||||||
deps =
|
deps =
|
||||||
{[testenv:build]deps}
|
{[testenv:build]deps}
|
||||||
|
|
@ -159,5 +140,3 @@ exclude =
|
||||||
.cache,
|
.cache,
|
||||||
.eggs
|
.eggs
|
||||||
max-complexity = 10
|
max-complexity = 10
|
||||||
import-order-style = google
|
|
||||||
application-import-names = flake8
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue