mirror of
https://github.com/PyCQA/flake8.git
synced 2026-03-29 10:36:53 +00:00
Compare commits
35 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d75094913 | ||
|
|
941f908d6c | ||
|
|
7abc22bd96 | ||
|
|
45c1af5e24 | ||
|
|
a358fc3f6b | ||
|
|
72c267d2e5 | ||
|
|
b84b2bd4a1 | ||
|
|
01af84d980 | ||
|
|
5fd56a3013 | ||
|
|
e7682d020c | ||
|
|
fcfa2cd490 | ||
|
|
567cafc15a | ||
|
|
d45bdc05ce | ||
|
|
e9f1cf3f48 | ||
|
|
ed8ac7bdc2 | ||
|
|
4b13c2cc19 | ||
|
|
2b3d18f0e9 | ||
|
|
3a2eff0868 | ||
|
|
fa4493de4b | ||
|
|
0f1af50108 | ||
|
|
8fdc755d6b | ||
|
|
5fab0d1887 | ||
|
|
23d2a8517e | ||
|
|
628aece714 | ||
|
|
c48217e1fc | ||
|
|
f9e0f33281 | ||
|
|
6bcdb62859 | ||
|
|
70a15b8890 | ||
|
|
4941a3e32e | ||
|
|
23e4005c55 | ||
|
|
019424b80d | ||
|
|
6b6f3d5fef | ||
|
|
8dfa6695b4 | ||
|
|
ce34111183 | ||
|
|
3613896bd9 |
42 changed files with 233 additions and 195 deletions
14
.github/workflows/main.yml
vendored
14
.github/workflows/main.yml
vendored
|
|
@ -13,10 +13,7 @@ jobs:
|
||||||
include:
|
include:
|
||||||
# linux
|
# linux
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
python: pypy-3.9
|
python: pypy-3.11
|
||||||
toxenv: py
|
|
||||||
- os: ubuntu-latest
|
|
||||||
python: 3.9
|
|
||||||
toxenv: py
|
toxenv: py
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
python: '3.10'
|
python: '3.10'
|
||||||
|
|
@ -30,9 +27,12 @@ jobs:
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
python: '3.13'
|
python: '3.13'
|
||||||
toxenv: py
|
toxenv: py
|
||||||
|
- os: ubuntu-latest
|
||||||
|
python: '3.14'
|
||||||
|
toxenv: py
|
||||||
# windows
|
# windows
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python: 3.9
|
python: '3.10'
|
||||||
toxenv: py
|
toxenv: py
|
||||||
# misc
|
# misc
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
|
|
@ -46,8 +46,8 @@ jobs:
|
||||||
toxenv: dogfood
|
toxenv: dogfood
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
- run: python -mpip install --upgrade setuptools pip tox virtualenv
|
- run: python -mpip install --upgrade setuptools pip tox virtualenv
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
repos:
|
repos:
|
||||||
|
- repo: https://github.com/asottile/add-trailing-comma
|
||||||
|
rev: v4.0.0
|
||||||
|
hooks:
|
||||||
|
- id: add-trailing-comma
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.5.0
|
rev: v6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
- id: debug-statements
|
- id: debug-statements
|
||||||
|
|
@ -8,34 +12,33 @@ repos:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
exclude: ^tests/fixtures/
|
exclude: ^tests/fixtures/
|
||||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||||
rev: v2.5.0
|
rev: v3.2.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: setup-cfg-fmt
|
- id: setup-cfg-fmt
|
||||||
- repo: https://github.com/asottile/reorder-python-imports
|
- repo: https://github.com/asottile/reorder-python-imports
|
||||||
rev: v3.14.0
|
rev: v3.16.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: reorder-python-imports
|
- id: reorder-python-imports
|
||||||
args: [
|
args: [
|
||||||
--application-directories, '.:src',
|
--application-directories, '.:src',
|
||||||
--py39-plus,
|
--py310-plus,
|
||||||
--add-import, 'from __future__ import annotations',
|
--add-import, 'from __future__ import annotations',
|
||||||
]
|
]
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v3.19.1
|
rev: v3.21.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py39-plus]
|
args: [--py310-plus]
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/hhatto/autopep8
|
||||||
rev: 23.12.1
|
rev: v2.3.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: autopep8
|
||||||
args: [--line-length=79]
|
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
rev: 7.0.0
|
rev: 7.3.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v1.15.0
|
rev: v1.19.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
exclude: ^(docs/|example-plugin/)
|
exclude: ^(docs/|example-plugin/)
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,5 @@ python:
|
||||||
install:
|
install:
|
||||||
- path: .
|
- path: .
|
||||||
- requirements: docs/source/requirements.txt
|
- requirements: docs/source/requirements.txt
|
||||||
|
sphinx:
|
||||||
|
configuration: docs/source/conf.py
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ from __future__ import annotations
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import os.path
|
import os.path
|
||||||
|
from collections.abc import Callable
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
import pycodestyle
|
import pycodestyle
|
||||||
|
|
|
||||||
15
docs/source/release-notes/7.3.0.rst
Normal file
15
docs/source/release-notes/7.3.0.rst
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
7.3.0 -- 2025-06-20
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
You can view the `7.3.0 milestone`_ on GitHub for more details.
|
||||||
|
|
||||||
|
New Dependency Information
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
- Added support for python 3.14 (See also :pull:`1983`).
|
||||||
|
- pycodestyle has been updated to >= 2.14.0, < 2.15.0 (See also :pull:`1985`).
|
||||||
|
- Pyflakes has been updated to >= 3.4.0, < 3.5.0 (See also :pull:`1985`).
|
||||||
|
|
||||||
|
.. all links
|
||||||
|
.. _7.3.0 milestone:
|
||||||
|
https://github.com/PyCQA/flake8/milestone/54
|
||||||
|
|
@ -9,18 +9,19 @@ with the newest releases first.
|
||||||
==================
|
==================
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
7.0.0
|
7.3.0
|
||||||
7.1.0
|
|
||||||
7.1.1
|
|
||||||
7.1.2
|
|
||||||
7.2.0
|
7.2.0
|
||||||
|
7.1.2
|
||||||
|
7.1.1
|
||||||
|
7.1.0
|
||||||
|
7.0.0
|
||||||
|
|
||||||
6.x Release Series
|
6.x Release Series
|
||||||
==================
|
==================
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
6.0.0
|
|
||||||
6.1.0
|
6.1.0
|
||||||
|
6.0.0
|
||||||
|
|
||||||
5.x Release Series
|
5.x Release Series
|
||||||
==================
|
==================
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@ generates its own :term:`error code`\ s for ``pyflakes``:
|
||||||
+------+---------------------------------------------------------------------+
|
+------+---------------------------------------------------------------------+
|
||||||
| F541 | f-string without any placeholders |
|
| F541 | f-string without any placeholders |
|
||||||
+------+---------------------------------------------------------------------+
|
+------+---------------------------------------------------------------------+
|
||||||
|
| F542 | t-string without any placeholders |
|
||||||
|
+------+---------------------------------------------------------------------+
|
||||||
+------+---------------------------------------------------------------------+
|
+------+---------------------------------------------------------------------+
|
||||||
| F601 | dictionary key ``name`` repeated with different values |
|
| F601 | dictionary key ``name`` repeated with different values |
|
||||||
+------+---------------------------------------------------------------------+
|
+------+---------------------------------------------------------------------+
|
||||||
|
|
@ -102,6 +104,9 @@ generates its own :term:`error code`\ s for ``pyflakes``:
|
||||||
+------+---------------------------------------------------------------------+
|
+------+---------------------------------------------------------------------+
|
||||||
| F823 | local variable ``name`` ... referenced before assignment |
|
| F823 | local variable ``name`` ... referenced before assignment |
|
||||||
+------+---------------------------------------------------------------------+
|
+------+---------------------------------------------------------------------+
|
||||||
|
| F824 | ``global name`` / ``nonlocal name`` is unused: name is never |
|
||||||
|
| | assigned in scope |
|
||||||
|
+------+---------------------------------------------------------------------+
|
||||||
| F831 | duplicate argument ``name`` in function definition |
|
| F831 | duplicate argument ``name`` in function definition |
|
||||||
+------+---------------------------------------------------------------------+
|
+------+---------------------------------------------------------------------+
|
||||||
| F841 | local variable ``name`` is assigned to but never used |
|
| F841 | local variable ``name`` is assigned to but never used |
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ classifiers =
|
||||||
Environment :: Console
|
Environment :: Console
|
||||||
Framework :: Flake8
|
Framework :: Flake8
|
||||||
Intended Audience :: Developers
|
Intended Audience :: Developers
|
||||||
License :: OSI Approved :: MIT License
|
|
||||||
Programming Language :: Python
|
Programming Language :: Python
|
||||||
Programming Language :: Python :: 3
|
Programming Language :: Python :: 3
|
||||||
Programming Language :: Python :: 3 :: Only
|
Programming Language :: Python :: 3 :: Only
|
||||||
|
|
@ -29,9 +28,9 @@ classifiers =
|
||||||
packages = find:
|
packages = find:
|
||||||
install_requires =
|
install_requires =
|
||||||
mccabe>=0.7.0,<0.8.0
|
mccabe>=0.7.0,<0.8.0
|
||||||
pycodestyle>=2.13.0,<2.14.0
|
pycodestyle>=2.14.0,<2.15.0
|
||||||
pyflakes>=3.3.0,<3.4.0
|
pyflakes>=3.4.0,<3.5.0
|
||||||
python_requires = >=3.9
|
python_requires = >=3.10
|
||||||
package_dir =
|
package_dir =
|
||||||
=src
|
=src
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import sys
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
LOG.addHandler(logging.NullHandler())
|
LOG.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
__version__ = "7.2.0"
|
__version__ = "7.3.0"
|
||||||
__version_info__ = tuple(int(i) for i in __version__.split(".") if i.isdigit())
|
__version_info__ = tuple(int(i) for i in __version__.split(".") if i.isdigit())
|
||||||
|
|
||||||
_VERBOSITY_TO_LOG_LEVEL = {
|
_VERBOSITY_TO_LOG_LEVEL = {
|
||||||
|
|
@ -66,5 +66,5 @@ def configure_logging(
|
||||||
LOG.addHandler(handler)
|
LOG.addHandler(handler)
|
||||||
LOG.setLevel(log_level)
|
LOG.setLevel(log_level)
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
"Added a %s logging handler to logger root at %s", filename, __name__
|
"Added a %s logging handler to logger root at %s", filename, __name__,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,10 @@ if sys.version_info >= (3, 12): # pragma: >=3.12 cover
|
||||||
FSTRING_END = tokenize.FSTRING_END
|
FSTRING_END = tokenize.FSTRING_END
|
||||||
else: # pragma: <3.12 cover
|
else: # pragma: <3.12 cover
|
||||||
FSTRING_START = FSTRING_MIDDLE = FSTRING_END = -1
|
FSTRING_START = FSTRING_MIDDLE = FSTRING_END = -1
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 14): # pragma: >=3.14 cover
|
||||||
|
TSTRING_START = tokenize.TSTRING_START
|
||||||
|
TSTRING_MIDDLE = tokenize.TSTRING_MIDDLE
|
||||||
|
TSTRING_END = tokenize.TSTRING_END
|
||||||
|
else: # pragma: <3.14 cover
|
||||||
|
TSTRING_START = TSTRING_MIDDLE = TSTRING_END = -1
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ class StyleGuide:
|
||||||
stdin_display_name=self.options.stdin_display_name,
|
stdin_display_name=self.options.stdin_display_name,
|
||||||
filename_patterns=self.options.filename,
|
filename_patterns=self.options.filename,
|
||||||
exclude=self.options.exclude,
|
exclude=self.options.exclude,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
return not paths
|
return not paths
|
||||||
|
|
||||||
|
|
@ -153,7 +153,7 @@ class StyleGuide:
|
||||||
if not issubclass(reporter, formatter.BaseFormatter):
|
if not issubclass(reporter, formatter.BaseFormatter):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Report should be subclass of "
|
"Report should be subclass of "
|
||||||
"flake8.formatter.BaseFormatter."
|
"flake8.formatter.BaseFormatter.",
|
||||||
)
|
)
|
||||||
self._application.formatter = reporter(self.options)
|
self._application.formatter = reporter(self.options)
|
||||||
self._application.guide = None
|
self._application.guide = None
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ from flake8 import exceptions
|
||||||
from flake8 import processor
|
from flake8 import processor
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
from flake8._compat import FSTRING_START
|
from flake8._compat import FSTRING_START
|
||||||
|
from flake8._compat import TSTRING_START
|
||||||
from flake8.discover_files import expand_paths
|
from flake8.discover_files import expand_paths
|
||||||
from flake8.options.parse_args import parse_args
|
from flake8.options.parse_args import parse_args
|
||||||
from flake8.plugins.finder import Checkers
|
from flake8.plugins.finder import Checkers
|
||||||
|
|
@ -44,40 +45,39 @@ SERIAL_RETRY_ERRNOS = {
|
||||||
# noise in diffs.
|
# noise in diffs.
|
||||||
}
|
}
|
||||||
|
|
||||||
_mp_plugins: Checkers
|
_mp: tuple[Checkers, argparse.Namespace] | None = None
|
||||||
_mp_options: argparse.Namespace
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def _mp_prefork(
|
def _mp_prefork(
|
||||||
plugins: Checkers, options: argparse.Namespace
|
plugins: Checkers, options: argparse.Namespace,
|
||||||
) -> Generator[None]:
|
) -> Generator[None]:
|
||||||
# we can save significant startup work w/ `fork` multiprocessing
|
# we can save significant startup work w/ `fork` multiprocessing
|
||||||
global _mp_plugins, _mp_options
|
global _mp
|
||||||
_mp_plugins, _mp_options = plugins, options
|
_mp = plugins, options
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
del _mp_plugins, _mp_options
|
_mp = None
|
||||||
|
|
||||||
|
|
||||||
def _mp_init(argv: Sequence[str]) -> None:
|
def _mp_init(argv: Sequence[str]) -> None:
|
||||||
global _mp_plugins, _mp_options
|
global _mp
|
||||||
|
|
||||||
# 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)
|
||||||
|
|
||||||
try:
|
# for `fork` this'll already be set
|
||||||
# for `fork` this'll already be set
|
if _mp is None:
|
||||||
_mp_plugins, _mp_options # noqa: B018
|
|
||||||
except NameError:
|
|
||||||
plugins, options = parse_args(argv)
|
plugins, options = parse_args(argv)
|
||||||
_mp_plugins, _mp_options = plugins.checkers, options
|
_mp = plugins.checkers, options
|
||||||
|
|
||||||
|
|
||||||
def _mp_run(filename: str) -> tuple[str, Results, dict[str, int]]:
|
def _mp_run(filename: str) -> tuple[str, Results, dict[str, int]]:
|
||||||
|
assert _mp is not None, _mp
|
||||||
|
plugins, options = _mp
|
||||||
return FileChecker(
|
return FileChecker(
|
||||||
filename=filename, plugins=_mp_plugins, options=_mp_options
|
filename=filename, plugins=plugins, options=options,
|
||||||
).run_checks()
|
).run_checks()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -137,7 +137,7 @@ class Manager:
|
||||||
if utils.is_using_stdin(self.options.filenames):
|
if utils.is_using_stdin(self.options.filenames):
|
||||||
LOG.warning(
|
LOG.warning(
|
||||||
"The --jobs option is not compatible with supplying "
|
"The --jobs option is not compatible with supplying "
|
||||||
"input using - . Ignoring --jobs arguments."
|
"input using - . Ignoring --jobs arguments.",
|
||||||
)
|
)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
@ -252,7 +252,7 @@ class Manager:
|
||||||
stdin_display_name=self.options.stdin_display_name,
|
stdin_display_name=self.options.stdin_display_name,
|
||||||
filename_patterns=self.options.filename,
|
filename_patterns=self.options.filename,
|
||||||
exclude=self.exclude,
|
exclude=self.exclude,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
self.jobs = min(len(self.filenames), self.jobs)
|
self.jobs = min(len(self.filenames), self.jobs)
|
||||||
|
|
||||||
|
|
@ -332,11 +332,11 @@ class FileChecker:
|
||||||
assert self.processor is not None, self.filename
|
assert self.processor is not None, self.filename
|
||||||
try:
|
try:
|
||||||
params = self.processor.keyword_arguments_for(
|
params = self.processor.keyword_arguments_for(
|
||||||
plugin.parameters, arguments
|
plugin.parameters, arguments,
|
||||||
)
|
)
|
||||||
except AttributeError as ae:
|
except AttributeError as ae:
|
||||||
raise exceptions.PluginRequestedUnknownParameters(
|
raise exceptions.PluginRequestedUnknownParameters(
|
||||||
plugin_name=plugin.display_name, exception=ae
|
plugin_name=plugin.display_name, exception=ae,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
return plugin.obj(**arguments, **params)
|
return plugin.obj(**arguments, **params)
|
||||||
|
|
@ -372,43 +372,6 @@ class FileChecker:
|
||||||
token = ()
|
token = ()
|
||||||
row, column = (1, 0)
|
row, column = (1, 0)
|
||||||
|
|
||||||
if (
|
|
||||||
column > 0
|
|
||||||
and token
|
|
||||||
and isinstance(exception, SyntaxError)
|
|
||||||
and len(token) == 4 # Python 3.9 or earlier
|
|
||||||
):
|
|
||||||
# NOTE(sigmavirus24): SyntaxErrors report 1-indexed column
|
|
||||||
# numbers. We need to decrement the column number by 1 at
|
|
||||||
# least.
|
|
||||||
column_offset = 1
|
|
||||||
row_offset = 0
|
|
||||||
# See also: https://github.com/pycqa/flake8/issues/169,
|
|
||||||
# https://github.com/PyCQA/flake8/issues/1372
|
|
||||||
# On Python 3.9 and earlier, token will be a 4-item tuple with the
|
|
||||||
# last item being the string. Starting with 3.10, they added to
|
|
||||||
# the tuple so now instead of it ending with the code that failed
|
|
||||||
# to parse, it ends with the end of the section of code that
|
|
||||||
# failed to parse. Luckily the absolute position in the tuple is
|
|
||||||
# stable across versions so we can use that here
|
|
||||||
physical_line = token[3]
|
|
||||||
|
|
||||||
# NOTE(sigmavirus24): Not all "tokens" have a string as the last
|
|
||||||
# argument. In this event, let's skip trying to find the correct
|
|
||||||
# column and row values.
|
|
||||||
if physical_line is not None:
|
|
||||||
# NOTE(sigmavirus24): SyntaxErrors also don't exactly have a
|
|
||||||
# "physical" line so much as what was accumulated by the point
|
|
||||||
# tokenizing failed.
|
|
||||||
# See also: https://github.com/pycqa/flake8/issues/169
|
|
||||||
lines = physical_line.rstrip("\n").split("\n")
|
|
||||||
row_offset = len(lines) - 1
|
|
||||||
logical_line = lines[0]
|
|
||||||
logical_line_length = len(logical_line)
|
|
||||||
if column > logical_line_length:
|
|
||||||
column = logical_line_length
|
|
||||||
row -= row_offset
|
|
||||||
column -= column_offset
|
|
||||||
return row, column
|
return row, column
|
||||||
|
|
||||||
def run_ast_checks(self) -> None:
|
def run_ast_checks(self) -> None:
|
||||||
|
|
@ -548,12 +511,14 @@ class FileChecker:
|
||||||
self.run_logical_checks()
|
self.run_logical_checks()
|
||||||
|
|
||||||
def check_physical_eol(
|
def check_physical_eol(
|
||||||
self, token: tokenize.TokenInfo, prev_physical: str
|
self, token: tokenize.TokenInfo, prev_physical: str,
|
||||||
) -> None:
|
) -> 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."""
|
||||||
assert self.processor is not None
|
assert self.processor is not None
|
||||||
if token.type == FSTRING_START: # pragma: >=3.12 cover
|
if token.type == FSTRING_START: # pragma: >=3.12 cover
|
||||||
self.processor.fstring_start(token.start[0])
|
self.processor.fstring_start(token.start[0])
|
||||||
|
elif token.type == TSTRING_START: # pragma: >=3.14 cover
|
||||||
|
self.processor.tstring_start(token.start[0])
|
||||||
# a newline token ends a single physical line.
|
# a newline token ends a single physical line.
|
||||||
elif processor.is_eol_token(token):
|
elif processor.is_eol_token(token):
|
||||||
# if the file does not end with a newline, the NEWLINE
|
# if the file does not end with a newline, the NEWLINE
|
||||||
|
|
@ -596,7 +561,7 @@ def _try_initialize_processpool(
|
||||||
|
|
||||||
|
|
||||||
def find_offset(
|
def find_offset(
|
||||||
offset: int, mapping: processor._LogicalMapping
|
offset: int, mapping: processor._LogicalMapping,
|
||||||
) -> tuple[int, int]:
|
) -> 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):
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
|
from collections.abc import Callable
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from typing import Callable
|
|
||||||
|
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ class BaseFormatter:
|
||||||
The formatted error string.
|
The formatted error string.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"Subclass of BaseFormatter did not implement" " format."
|
"Subclass of BaseFormatter did not implement" " format.",
|
||||||
)
|
)
|
||||||
|
|
||||||
def show_statistics(self, statistics: Statistics) -> None:
|
def show_statistics(self, statistics: Statistics) -> None:
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ class Application:
|
||||||
assert self.formatter is not None
|
assert self.formatter is not None
|
||||||
assert self.options is not None
|
assert self.options is not None
|
||||||
self.guide = style_guide.StyleGuideManager(
|
self.guide = style_guide.StyleGuideManager(
|
||||||
self.options, self.formatter
|
self.options, self.formatter,
|
||||||
)
|
)
|
||||||
|
|
||||||
def make_file_checker_manager(self, argv: Sequence[str]) -> None:
|
def make_file_checker_manager(self, argv: Sequence[str]) -> None:
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ def information(version: str, plugins: Plugins) -> dict[str, Any]:
|
||||||
(loaded.plugin.package, loaded.plugin.version)
|
(loaded.plugin.package, loaded.plugin.version)
|
||||||
for loaded in plugins.all_plugins()
|
for loaded in plugins.all_plugins()
|
||||||
if loaded.plugin.package not in {"flake8", "local"}
|
if loaded.plugin.package not in {"flake8", "local"}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
"version": version,
|
"version": version,
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ def stage1_arg_parser() -> argparse.ArgumentParser:
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--output-file", default=None, help="Redirect report to a file."
|
"--output-file", default=None, help="Redirect report to a file.",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Config file options
|
# Config file options
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ def load_config(
|
||||||
if config is not None:
|
if config is not None:
|
||||||
if not cfg.read(config, encoding="UTF-8"):
|
if not cfg.read(config, encoding="UTF-8"):
|
||||||
raise exceptions.ExecutionError(
|
raise exceptions.ExecutionError(
|
||||||
f"The specified config file does not exist: {config}"
|
f"The specified config file does not exist: {config}",
|
||||||
)
|
)
|
||||||
cfg_dir = os.path.dirname(config)
|
cfg_dir = os.path.dirname(config)
|
||||||
else:
|
else:
|
||||||
|
|
@ -89,7 +89,7 @@ def load_config(
|
||||||
for filename in extra:
|
for filename in extra:
|
||||||
if not cfg.read(filename, encoding="UTF-8"):
|
if not cfg.read(filename, encoding="UTF-8"):
|
||||||
raise exceptions.ExecutionError(
|
raise exceptions.ExecutionError(
|
||||||
f"The specified config file does not exist: {filename}"
|
f"The specified config file does not exist: {filename}",
|
||||||
)
|
)
|
||||||
|
|
||||||
return cfg, cfg_dir
|
return cfg, cfg_dir
|
||||||
|
|
@ -131,7 +131,7 @@ def parse_config(
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Error code {error_code!r} "
|
f"Error code {error_code!r} "
|
||||||
f"supplied to {option_name!r} option "
|
f"supplied to {option_name!r} option "
|
||||||
f"does not match {VALID_CODE_PREFIX.pattern!r}"
|
f"does not match {VALID_CODE_PREFIX.pattern!r}",
|
||||||
)
|
)
|
||||||
|
|
||||||
assert option.config_name is not None
|
assert option.config_name is not None
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import argparse
|
||||||
import enum
|
import enum
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
|
from collections.abc import Callable
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
|
||||||
|
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
from flake8.plugins.finder import Plugins
|
from flake8.plugins.finder import Plugins
|
||||||
|
|
@ -165,7 +165,7 @@ class Option:
|
||||||
if long_option_name is _ARG.NO:
|
if long_option_name is _ARG.NO:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"When specifying parse_from_config=True, "
|
"When specifying parse_from_config=True, "
|
||||||
"a long_option_name must also be specified."
|
"a long_option_name must also be specified.",
|
||||||
)
|
)
|
||||||
self.config_name = long_option_name[2:].replace("-", "_")
|
self.config_name = long_option_name[2:].replace("-", "_")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,8 +83,8 @@ class Plugins(NamedTuple):
|
||||||
f"{loaded.plugin.package}: {loaded.plugin.version}"
|
f"{loaded.plugin.package}: {loaded.plugin.version}"
|
||||||
for loaded in self.all_plugins()
|
for loaded in self.all_plugins()
|
||||||
if loaded.plugin.package not in {"flake8", "local"}
|
if loaded.plugin.package not in {"flake8", "local"}
|
||||||
}
|
},
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -167,7 +167,7 @@ def _flake8_plugins(
|
||||||
# ideally pycodestyle's plugin entrypoints would exactly represent
|
# ideally pycodestyle's plugin entrypoints would exactly represent
|
||||||
# the codes they produce...
|
# the codes they produce...
|
||||||
yield Plugin(
|
yield Plugin(
|
||||||
pycodestyle_meta["name"], pycodestyle_meta["version"], ep
|
pycodestyle_meta["name"], pycodestyle_meta["version"], ep,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
yield Plugin(name, version, ep)
|
yield Plugin(name, version, ep)
|
||||||
|
|
@ -240,7 +240,7 @@ def _check_required_plugins(
|
||||||
f"required plugins were not installed!\n"
|
f"required plugins were not installed!\n"
|
||||||
f"- installed: {', '.join(sorted(plugin_names))}\n"
|
f"- installed: {', '.join(sorted(plugin_names))}\n"
|
||||||
f"- expected: {', '.join(sorted(expected_names))}\n"
|
f"- expected: {', '.join(sorted(expected_names))}\n"
|
||||||
f"- missing: {', '.join(sorted(missing_plugins))}"
|
f"- missing: {', '.join(sorted(missing_plugins))}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -338,7 +338,7 @@ def _classify_plugins(
|
||||||
if not VALID_CODE_PREFIX.match(loaded.entry_name):
|
if not VALID_CODE_PREFIX.match(loaded.entry_name):
|
||||||
raise ExecutionError(
|
raise ExecutionError(
|
||||||
f"plugin code for `{loaded.display_name}` does not match "
|
f"plugin code for `{loaded.display_name}` does not match "
|
||||||
f"{VALID_CODE_PREFIX.pattern}"
|
f"{VALID_CODE_PREFIX.pattern}",
|
||||||
)
|
)
|
||||||
|
|
||||||
return Plugins(
|
return Plugins(
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ FLAKE8_PYFLAKES_CODES = {
|
||||||
"StringDotFormatMissingArgument": "F524",
|
"StringDotFormatMissingArgument": "F524",
|
||||||
"StringDotFormatMixingAutomatic": "F525",
|
"StringDotFormatMixingAutomatic": "F525",
|
||||||
"FStringMissingPlaceholders": "F541",
|
"FStringMissingPlaceholders": "F541",
|
||||||
|
"TStringMissingPlaceholders": "F542",
|
||||||
"MultiValueRepeatedKeyLiteral": "F601",
|
"MultiValueRepeatedKeyLiteral": "F601",
|
||||||
"MultiValueRepeatedKeyVariable": "F602",
|
"MultiValueRepeatedKeyVariable": "F602",
|
||||||
"TooManyExpressionsInStarredAssignment": "F621",
|
"TooManyExpressionsInStarredAssignment": "F621",
|
||||||
|
|
@ -71,7 +72,7 @@ class FlakesChecker(pyflakes.checker.Checker):
|
||||||
def __init__(self, tree: ast.AST, filename: str) -> None:
|
def __init__(self, tree: ast.AST, filename: str) -> None:
|
||||||
"""Initialize the PyFlakes plugin with an AST tree and filename."""
|
"""Initialize the PyFlakes plugin with an AST tree and filename."""
|
||||||
super().__init__(
|
super().__init__(
|
||||||
tree, filename=filename, withDoctest=self.with_doctest
|
tree, filename=filename, withDoctest=self.with_doctest,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,15 @@ from flake8 import defaults
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
from flake8._compat import FSTRING_END
|
from flake8._compat import FSTRING_END
|
||||||
from flake8._compat import FSTRING_MIDDLE
|
from flake8._compat import FSTRING_MIDDLE
|
||||||
|
from flake8._compat import TSTRING_END
|
||||||
|
from flake8._compat import TSTRING_MIDDLE
|
||||||
from flake8.plugins.finder import LoadedPlugin
|
from flake8.plugins.finder import LoadedPlugin
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE])
|
NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE])
|
||||||
|
|
||||||
SKIP_TOKENS = frozenset(
|
SKIP_TOKENS = frozenset(
|
||||||
[tokenize.NL, tokenize.NEWLINE, tokenize.INDENT, tokenize.DEDENT]
|
[tokenize.NL, tokenize.NEWLINE, tokenize.INDENT, tokenize.DEDENT],
|
||||||
)
|
)
|
||||||
|
|
||||||
_LogicalMapping = list[tuple[int, tuple[int, int]]]
|
_LogicalMapping = list[tuple[int, tuple[int, int]]]
|
||||||
|
|
@ -113,7 +115,7 @@ class FileProcessor:
|
||||||
self.verbose = options.verbose
|
self.verbose = options.verbose
|
||||||
#: Statistics dictionary
|
#: Statistics dictionary
|
||||||
self.statistics = {"logical lines": 0}
|
self.statistics = {"logical lines": 0}
|
||||||
self._fstring_start = -1
|
self._fstring_start = self._tstring_start = -1
|
||||||
|
|
||||||
@functools.cached_property
|
@functools.cached_property
|
||||||
def file_tokens(self) -> list[tokenize.TokenInfo]:
|
def file_tokens(self) -> list[tokenize.TokenInfo]:
|
||||||
|
|
@ -125,10 +127,16 @@ class FileProcessor:
|
||||||
"""Signal the beginning of an fstring."""
|
"""Signal the beginning of an fstring."""
|
||||||
self._fstring_start = lineno
|
self._fstring_start = lineno
|
||||||
|
|
||||||
|
def tstring_start(self, lineno: int) -> None: # pragma: >=3.14 cover
|
||||||
|
"""Signal the beginning of an tstring."""
|
||||||
|
self._tstring_start = lineno
|
||||||
|
|
||||||
def multiline_string(self, token: tokenize.TokenInfo) -> Generator[str]:
|
def multiline_string(self, token: tokenize.TokenInfo) -> Generator[str]:
|
||||||
"""Iterate through the lines of a multiline string."""
|
"""Iterate through the lines of a multiline string."""
|
||||||
if token.type == FSTRING_END: # pragma: >=3.12 cover
|
if token.type == FSTRING_END: # pragma: >=3.12 cover
|
||||||
start = self._fstring_start
|
start = self._fstring_start
|
||||||
|
elif token.type == TSTRING_END: # pragma: >=3.14 cover
|
||||||
|
start = self._tstring_start
|
||||||
else:
|
else:
|
||||||
start = token.start[0]
|
start = token.start[0]
|
||||||
|
|
||||||
|
|
@ -165,7 +173,7 @@ class FileProcessor:
|
||||||
"""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.entry_name, {}
|
plugin.entry_name, {},
|
||||||
)
|
)
|
||||||
|
|
||||||
def next_logical_line(self) -> None:
|
def next_logical_line(self) -> None:
|
||||||
|
|
@ -198,7 +206,10 @@ class FileProcessor:
|
||||||
continue
|
continue
|
||||||
if token_type == tokenize.STRING:
|
if token_type == tokenize.STRING:
|
||||||
text = mutate_string(text)
|
text = mutate_string(text)
|
||||||
elif token_type == FSTRING_MIDDLE: # pragma: >=3.12 cover
|
elif token_type in {
|
||||||
|
FSTRING_MIDDLE,
|
||||||
|
TSTRING_MIDDLE,
|
||||||
|
}: # pragma: >=3.12 cover # noqa: E501
|
||||||
# A curly brace in an FSTRING_MIDDLE token must be an escaped
|
# A curly brace in an FSTRING_MIDDLE token must be an escaped
|
||||||
# curly brace. Both 'text' and 'end' will account for the
|
# curly brace. Both 'text' and 'end' will account for the
|
||||||
# escaped version of the token (i.e. a single brace) rather
|
# escaped version of the token (i.e. a single brace) rather
|
||||||
|
|
@ -269,7 +280,7 @@ class FileProcessor:
|
||||||
|
|
||||||
def _noqa_line_range(self, min_line: int, max_line: int) -> dict[int, str]:
|
def _noqa_line_range(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)
|
||||||
|
|
||||||
@functools.cached_property
|
@functools.cached_property
|
||||||
|
|
@ -356,7 +367,7 @@ class FileProcessor:
|
||||||
elif any(defaults.NOQA_FILE.search(line) for line in self.lines):
|
elif any(defaults.NOQA_FILE.search(line) for line in self.lines):
|
||||||
LOG.warning(
|
LOG.warning(
|
||||||
"Detected `flake8: noqa` on line with code. To ignore an "
|
"Detected `flake8: noqa` on line with code. To ignore an "
|
||||||
"error on a line use `noqa` instead."
|
"error on a line use `noqa` instead.",
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
|
@ -377,12 +388,12 @@ class FileProcessor:
|
||||||
|
|
||||||
def is_eol_token(token: tokenize.TokenInfo) -> bool:
|
def is_eol_token(token: tokenize.TokenInfo) -> 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: tokenize.TokenInfo) -> bool:
|
def is_multiline_string(token: tokenize.TokenInfo) -> bool:
|
||||||
"""Check if this is a multiline string."""
|
"""Check if this is a multiline string."""
|
||||||
return token.type == FSTRING_END or (
|
return token.type in {FSTRING_END, TSTRING_END} or (
|
||||||
token.type == tokenize.STRING and "\n" in token.string
|
token.type == tokenize.STRING and "\n" in token.string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class Statistics:
|
||||||
self._store[key].increment()
|
self._store[key].increment()
|
||||||
|
|
||||||
def statistics_for(
|
def statistics_for(
|
||||||
self, prefix: str, filename: str | None = None
|
self, prefix: str, filename: str | None = None,
|
||||||
) -> Generator[Statistic]:
|
) -> Generator[Statistic]:
|
||||||
"""Generate statistics for the prefix and filename.
|
"""Generate statistics for the prefix and filename.
|
||||||
|
|
||||||
|
|
@ -108,7 +108,7 @@ class Statistic:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, error_code: str, filename: str, message: str, count: int
|
self, error_code: str, filename: str, message: str, count: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize our Statistic."""
|
"""Initialize our Statistic."""
|
||||||
self.error_code = error_code
|
self.error_code = error_code
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ class StyleGuideManager:
|
||||||
self.decider = decider or DecisionEngine(options)
|
self.decider = decider or DecisionEngine(options)
|
||||||
self.style_guides: 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,
|
||||||
)
|
)
|
||||||
self.style_guides = [
|
self.style_guides = [
|
||||||
self.default_style_guide,
|
self.default_style_guide,
|
||||||
|
|
@ -228,7 +228,7 @@ class StyleGuideManager:
|
||||||
self.style_guide_for = functools.cache(self._style_guide_for)
|
self.style_guide_for = functools.cache(self._style_guide_for)
|
||||||
|
|
||||||
def populate_style_guides_with(
|
def populate_style_guides_with(
|
||||||
self, options: argparse.Namespace
|
self, options: argparse.Namespace,
|
||||||
) -> Generator[StyleGuide]:
|
) -> Generator[StyleGuide]:
|
||||||
"""Generate style guides from the per-file-ignores option.
|
"""Generate style guides from the per-file-ignores option.
|
||||||
|
|
||||||
|
|
@ -240,7 +240,7 @@ class StyleGuideManager:
|
||||||
per_file = utils.parse_files_to_codes_mapping(options.per_file_ignores)
|
per_file = utils.parse_files_to_codes_mapping(options.per_file_ignores)
|
||||||
for filename, violations in per_file:
|
for filename, violations in per_file:
|
||||||
yield self.default_style_guide.copy(
|
yield self.default_style_guide.copy(
|
||||||
filename=filename, extend_ignore_with=violations
|
filename=filename, extend_ignore_with=violations,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _style_guide_for(self, filename: str) -> StyleGuide:
|
def _style_guide_for(self, filename: str) -> StyleGuide:
|
||||||
|
|
@ -288,7 +288,7 @@ class StyleGuideManager:
|
||||||
"""
|
"""
|
||||||
guide = self.style_guide_for(filename)
|
guide = self.style_guide_for(filename)
|
||||||
return guide.handle_error(
|
return guide.handle_error(
|
||||||
code, filename, line_number, column_number, text, physical_line
|
code, filename, line_number, column_number, text, physical_line,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -330,7 +330,7 @@ class StyleGuide:
|
||||||
options.extend_ignore = options.extend_ignore or []
|
options.extend_ignore = options.extend_ignore or []
|
||||||
options.extend_ignore.extend(extend_ignore_with or [])
|
options.extend_ignore.extend(extend_ignore_with or [])
|
||||||
return StyleGuide(
|
return StyleGuide(
|
||||||
options, self.formatter, self.stats, filename=filename
|
options, self.formatter, self.stats, filename=filename,
|
||||||
)
|
)
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ NORMALIZE_PACKAGE_NAME_RE = re.compile(r"[-_.]+")
|
||||||
|
|
||||||
|
|
||||||
def parse_comma_separated_list(
|
def parse_comma_separated_list(
|
||||||
value: str, regexp: Pattern[str] = COMMA_SEPARATED_LIST_RE
|
value: str, regexp: Pattern[str] = COMMA_SEPARATED_LIST_RE,
|
||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
"""Parse a comma-separated list.
|
"""Parse a comma-separated list.
|
||||||
|
|
||||||
|
|
@ -115,7 +115,7 @@ def parse_files_to_codes_mapping( # noqa: C901
|
||||||
f"Expected `per-file-ignores` to be a mapping from file exclude "
|
f"Expected `per-file-ignores` to be a mapping from file exclude "
|
||||||
f"patterns to ignore codes.\n\n"
|
f"patterns to ignore codes.\n\n"
|
||||||
f"Configured `per-file-ignores` setting:\n\n"
|
f"Configured `per-file-ignores` setting:\n\n"
|
||||||
f"{textwrap.indent(value.strip(), ' ')}"
|
f"{textwrap.indent(value.strip(), ' ')}",
|
||||||
)
|
)
|
||||||
|
|
||||||
for token in _tokenize_files_to_codes_mapping(value):
|
for token in _tokenize_files_to_codes_mapping(value):
|
||||||
|
|
@ -150,7 +150,7 @@ def parse_files_to_codes_mapping( # noqa: C901
|
||||||
|
|
||||||
|
|
||||||
def normalize_paths(
|
def normalize_paths(
|
||||||
paths: Sequence[str], parent: str = os.curdir
|
paths: Sequence[str], parent: str = os.curdir,
|
||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
"""Normalize a list of paths relative to a parent directory.
|
"""Normalize a list of paths relative to a parent directory.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,6 @@ class Violation(NamedTuple):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
"%r is not ignored inline with ``# noqa: %s``", self, codes_str
|
"%r is not ignored inline with ``# noqa: %s``", self, codes_str,
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import importlib.metadata
|
import importlib.metadata
|
||||||
import sys
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
@ -97,7 +96,7 @@ def mock_file_checker_with_plugin(plugin_target):
|
||||||
|
|
||||||
# Prevent it from reading lines from stdin or somewhere else
|
# Prevent it from reading lines from stdin or somewhere else
|
||||||
with mock.patch(
|
with mock.patch(
|
||||||
"flake8.processor.FileProcessor.read_lines", return_value=["Line 1"]
|
"flake8.processor.FileProcessor.read_lines", return_value=["Line 1"],
|
||||||
):
|
):
|
||||||
file_checker = checker.FileChecker(
|
file_checker = checker.FileChecker(
|
||||||
filename="-",
|
filename="-",
|
||||||
|
|
@ -322,17 +321,10 @@ def test_handling_syntaxerrors_across_pythons():
|
||||||
We need to handle that correctly to avoid crashing.
|
We need to handle that correctly to avoid crashing.
|
||||||
https://github.com/PyCQA/flake8/issues/1372
|
https://github.com/PyCQA/flake8/issues/1372
|
||||||
"""
|
"""
|
||||||
if sys.version_info < (3, 10): # pragma: no cover (<3.10)
|
err = SyntaxError(
|
||||||
# Python 3.9 or older
|
"invalid syntax", ("<unknown>", 2, 1, "bad python:\n", 2, 11),
|
||||||
err = SyntaxError(
|
)
|
||||||
"invalid syntax", ("<unknown>", 2, 5, "bad python:\n")
|
expected = (2, 1)
|
||||||
)
|
|
||||||
expected = (2, 4)
|
|
||||||
else: # pragma: no cover (3.10+)
|
|
||||||
err = SyntaxError(
|
|
||||||
"invalid syntax", ("<unknown>", 2, 1, "bad python:\n", 2, 11)
|
|
||||||
)
|
|
||||||
expected = (2, 1)
|
|
||||||
file_checker = checker.FileChecker(
|
file_checker = checker.FileChecker(
|
||||||
filename="-",
|
filename="-",
|
||||||
plugins=finder.Checkers([], [], []),
|
plugins=finder.Checkers([], [], []),
|
||||||
|
|
|
||||||
|
|
@ -168,10 +168,8 @@ def test_tokenization_error_but_not_syntax_error(tmpdir, capsys):
|
||||||
tmpdir.join("t.py").write("b'foo' \\\n")
|
tmpdir.join("t.py").write("b'foo' \\\n")
|
||||||
assert cli.main(["t.py"]) == 1
|
assert cli.main(["t.py"]) == 1
|
||||||
|
|
||||||
if hasattr(sys, "pypy_version_info"): # pragma: no cover (pypy)
|
if sys.implementation.name == "pypy": # pragma: no cover (pypy)
|
||||||
expected = "t.py:2:1: E999 SyntaxError: end of file (EOF) in multi-line statement\n" # noqa: E501
|
expected = "t.py:1:9: E999 SyntaxError: unexpected end of file (EOF) in multi-line statement\n" # noqa: E501
|
||||||
elif sys.version_info < (3, 10): # pragma: no cover (cp38+)
|
|
||||||
expected = "t.py:1:8: E999 SyntaxError: unexpected EOF while parsing\n"
|
|
||||||
else: # pragma: no cover (cp310+)
|
else: # pragma: no cover (cp310+)
|
||||||
expected = "t.py:1:10: E999 SyntaxError: unexpected EOF while parsing\n" # noqa: E501
|
expected = "t.py:1:10: E999 SyntaxError: unexpected EOF while parsing\n" # noqa: E501
|
||||||
|
|
||||||
|
|
@ -186,10 +184,8 @@ def test_tokenization_error_is_a_syntax_error(tmpdir, capsys):
|
||||||
tmpdir.join("t.py").write("if True:\n pass\n pass\n")
|
tmpdir.join("t.py").write("if True:\n pass\n pass\n")
|
||||||
assert cli.main(["t.py"]) == 1
|
assert cli.main(["t.py"]) == 1
|
||||||
|
|
||||||
if hasattr(sys, "pypy_version_info"): # pragma: no cover (pypy)
|
if sys.implementation.name == "pypy": # pragma: no cover (pypy)
|
||||||
expected = "t.py:3:2: E999 IndentationError: unindent does not match any outer indentation level\n" # noqa: E501
|
expected = "t.py:3:3: E999 IndentationError: unindent does not match any outer indentation level\n" # noqa: E501
|
||||||
elif sys.version_info < (3, 10): # pragma: no cover (<cp310)
|
|
||||||
expected = "t.py:3:5: E999 IndentationError: unindent does not match any outer indentation level\n" # noqa: E501
|
|
||||||
else: # pragma: no cover (cp310+)
|
else: # pragma: no cover (cp310+)
|
||||||
expected = "t.py:3:7: E999 IndentationError: unindent does not match any outer indentation level\n" # noqa: E501
|
expected = "t.py:3:7: E999 IndentationError: unindent does not match any outer indentation level\n" # noqa: E501
|
||||||
|
|
||||||
|
|
@ -314,7 +310,7 @@ def test_cli_config_option_respected(tmp_path):
|
||||||
"""\
|
"""\
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore = F401
|
ignore = F401
|
||||||
"""
|
""",
|
||||||
)
|
)
|
||||||
|
|
||||||
py_file = tmp_path / "t.py"
|
py_file = tmp_path / "t.py"
|
||||||
|
|
@ -330,7 +326,7 @@ def test_cli_isolated_overrides_config_option(tmp_path):
|
||||||
"""\
|
"""\
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore = F401
|
ignore = F401
|
||||||
"""
|
""",
|
||||||
)
|
)
|
||||||
|
|
||||||
py_file = tmp_path / "t.py"
|
py_file = tmp_path / "t.py"
|
||||||
|
|
@ -364,7 +360,7 @@ def test_output_file(tmpdir, capsys):
|
||||||
|
|
||||||
def test_early_keyboard_interrupt_does_not_crash(capsys):
|
def test_early_keyboard_interrupt_does_not_crash(capsys):
|
||||||
with mock.patch.object(
|
with mock.patch.object(
|
||||||
config, "load_config", side_effect=KeyboardInterrupt
|
config, "load_config", side_effect=KeyboardInterrupt,
|
||||||
):
|
):
|
||||||
assert cli.main(["does-not-exist"]) == 1
|
assert cli.main(["does-not-exist"]) == 1
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ def test_local_plugin_can_add_option(local_config):
|
||||||
stage1_args, rest = stage1_parser.parse_known_args(argv)
|
stage1_args, rest = stage1_parser.parse_known_args(argv)
|
||||||
|
|
||||||
cfg, cfg_dir = config.load_config(
|
cfg, cfg_dir = config.load_config(
|
||||||
config=stage1_args.config, extra=[], isolated=False
|
config=stage1_args.config, extra=[], isolated=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
opts = finder.parse_plugin_options(
|
opts = finder.parse_plugin_options(
|
||||||
|
|
@ -296,3 +296,36 @@ t.py:1:1: T001 "f'xxxxxxxxxxxxxxxxxxxxxxxx'"
|
||||||
"""
|
"""
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
assert out == expected
|
assert out == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xfail(sys.version_info < (3, 14), reason="3.14+")
|
||||||
|
def test_tstring_logical_line(tmpdir, capsys): # pragma: >=3.14 cover
|
||||||
|
cfg_s = f"""\
|
||||||
|
[flake8]
|
||||||
|
extend-ignore = F
|
||||||
|
[flake8:local-plugins]
|
||||||
|
extension =
|
||||||
|
T = {yields_logical_line.__module__}:{yields_logical_line.__name__}
|
||||||
|
"""
|
||||||
|
|
||||||
|
cfg = tmpdir.join("tox.ini")
|
||||||
|
cfg.write(cfg_s)
|
||||||
|
|
||||||
|
src = """\
|
||||||
|
t'''
|
||||||
|
hello {world}
|
||||||
|
'''
|
||||||
|
t'{{"{hello}": "{world}"}}'
|
||||||
|
"""
|
||||||
|
t_py = tmpdir.join("t.py")
|
||||||
|
t_py.write_binary(src.encode())
|
||||||
|
|
||||||
|
with tmpdir.as_cwd():
|
||||||
|
assert main(("t.py", "--config", str(cfg))) == 1
|
||||||
|
|
||||||
|
expected = """\
|
||||||
|
t.py:1:1: T001 "t'''xxxxxxx{world}x'''"
|
||||||
|
t.py:4:1: T001 "t'xxx{hello}xxxx{world}xxx'"
|
||||||
|
"""
|
||||||
|
out, err = capsys.readouterr()
|
||||||
|
assert out == expected
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ def test_plugins_all_plugins():
|
||||||
logical_line_plugin = _loaded(parameters={"logical_line": True})
|
logical_line_plugin = _loaded(parameters={"logical_line": True})
|
||||||
physical_line_plugin = _loaded(parameters={"physical_line": True})
|
physical_line_plugin = _loaded(parameters={"physical_line": True})
|
||||||
report_plugin = _loaded(
|
report_plugin = _loaded(
|
||||||
plugin=_plugin(ep=_ep(name="R", group="flake8.report"))
|
plugin=_plugin(ep=_ep(name="R", group="flake8.report")),
|
||||||
)
|
)
|
||||||
|
|
||||||
plugins = finder.Plugins(
|
plugins = finder.Plugins(
|
||||||
|
|
@ -200,14 +200,16 @@ def test_flake8_plugins(flake8_dist, mock_distribution):
|
||||||
"flake8",
|
"flake8",
|
||||||
"9001",
|
"9001",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
"default", "flake8.formatting.default:Default", "flake8.report"
|
"default",
|
||||||
|
"flake8.formatting.default:Default",
|
||||||
|
"flake8.report",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
finder.Plugin(
|
finder.Plugin(
|
||||||
"flake8",
|
"flake8",
|
||||||
"9001",
|
"9001",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
"pylint", "flake8.formatting.default:Pylint", "flake8.report"
|
"pylint", "flake8.formatting.default:Pylint", "flake8.report",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
@ -270,7 +272,7 @@ unrelated = unrelated:main
|
||||||
"flake8-foo",
|
"flake8-foo",
|
||||||
"1.2.3",
|
"1.2.3",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
"Q", "flake8_foo:Plugin", "flake8.extension"
|
"Q", "flake8_foo:Plugin", "flake8.extension",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
finder.Plugin(
|
finder.Plugin(
|
||||||
|
|
@ -304,21 +306,23 @@ unrelated = unrelated:main
|
||||||
"flake8",
|
"flake8",
|
||||||
"9001",
|
"9001",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
"default", "flake8.formatting.default:Default", "flake8.report"
|
"default",
|
||||||
|
"flake8.formatting.default:Default",
|
||||||
|
"flake8.report",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
finder.Plugin(
|
finder.Plugin(
|
||||||
"flake8",
|
"flake8",
|
||||||
"9001",
|
"9001",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
"pylint", "flake8.formatting.default:Pylint", "flake8.report"
|
"pylint", "flake8.formatting.default:Pylint", "flake8.report",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
finder.Plugin(
|
finder.Plugin(
|
||||||
"flake8-foo",
|
"flake8-foo",
|
||||||
"1.2.3",
|
"1.2.3",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
"foo", "flake8_foo:Formatter", "flake8.report"
|
"foo", "flake8_foo:Formatter", "flake8.report",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
@ -485,28 +489,30 @@ def test_find_plugins(
|
||||||
"flake8",
|
"flake8",
|
||||||
"9001",
|
"9001",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
"default", "flake8.formatting.default:Default", "flake8.report"
|
"default",
|
||||||
|
"flake8.formatting.default:Default",
|
||||||
|
"flake8.report",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
finder.Plugin(
|
finder.Plugin(
|
||||||
"flake8",
|
"flake8",
|
||||||
"9001",
|
"9001",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
"pylint", "flake8.formatting.default:Pylint", "flake8.report"
|
"pylint", "flake8.formatting.default:Pylint", "flake8.report",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
finder.Plugin(
|
finder.Plugin(
|
||||||
"flake8-foo",
|
"flake8-foo",
|
||||||
"1.2.3",
|
"1.2.3",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
"Q", "flake8_foo:Plugin", "flake8.extension"
|
"Q", "flake8_foo:Plugin", "flake8.extension",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
finder.Plugin(
|
finder.Plugin(
|
||||||
"flake8-foo",
|
"flake8-foo",
|
||||||
"1.2.3",
|
"1.2.3",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
"foo", "flake8_foo:Formatter", "flake8.report"
|
"foo", "flake8_foo:Formatter", "flake8.report",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
finder.Plugin(
|
finder.Plugin(
|
||||||
|
|
@ -518,7 +524,7 @@ def test_find_plugins(
|
||||||
"local",
|
"local",
|
||||||
"local",
|
"local",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
"Y", "mod2:attr", "flake8.extension"
|
"Y", "mod2:attr", "flake8.extension",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
finder.Plugin(
|
finder.Plugin(
|
||||||
|
|
@ -723,7 +729,7 @@ def test_import_plugins_extends_sys_path():
|
||||||
|
|
||||||
def test_classify_plugins():
|
def test_classify_plugins():
|
||||||
report_plugin = _loaded(
|
report_plugin = _loaded(
|
||||||
plugin=_plugin(ep=_ep(name="R", group="flake8.report"))
|
plugin=_plugin(ep=_ep(name="R", group="flake8.report")),
|
||||||
)
|
)
|
||||||
tree_plugin = _loaded(parameters={"tree": True})
|
tree_plugin = _loaded(parameters={"tree": True})
|
||||||
logical_line_plugin = _loaded(parameters={"logical_line": True})
|
logical_line_plugin = _loaded(parameters={"logical_line": True})
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ def reporters():
|
||||||
"flake8",
|
"flake8",
|
||||||
"123",
|
"123",
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
name, f"{cls.__module__}:{cls.__name__}", "flake8.report"
|
name, f"{cls.__module__}:{cls.__name__}", "flake8.report",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
cls,
|
cls,
|
||||||
|
|
@ -72,5 +72,5 @@ def test_make_formatter_format_string(reporters, caplog):
|
||||||
"flake8.plugins.reporter",
|
"flake8.plugins.reporter",
|
||||||
30,
|
30,
|
||||||
"'hi %(code)s' is an unknown formatter. Falling back to default.",
|
"'hi %(code)s' is an unknown formatter. Falling back to default.",
|
||||||
)
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ def application():
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_application_exit_code(
|
def test_application_exit_code(
|
||||||
result_count, catastrophic, exit_zero, value, application
|
result_count, catastrophic, exit_zero, value, application,
|
||||||
):
|
):
|
||||||
"""Verify Application.exit_code returns the correct value."""
|
"""Verify Application.exit_code returns the correct value."""
|
||||||
application.result_count = result_count
|
application.result_count = result_count
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ def test_format_needs_to_be_implemented():
|
||||||
formatter = base.BaseFormatter(options())
|
formatter = base.BaseFormatter(options())
|
||||||
with pytest.raises(NotImplementedError):
|
with pytest.raises(NotImplementedError):
|
||||||
formatter.format(
|
formatter.format(
|
||||||
Violation("A000", "file.py", 1, 1, "error text", None)
|
Violation("A000", "file.py", 1, 1, "error text", None),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -59,7 +59,7 @@ def test_show_source_returns_nothing_when_not_showing_source():
|
||||||
formatter = base.BaseFormatter(options(show_source=False))
|
formatter = base.BaseFormatter(options(show_source=False))
|
||||||
assert (
|
assert (
|
||||||
formatter.show_source(
|
formatter.show_source(
|
||||||
Violation("A000", "file.py", 1, 1, "error text", "line")
|
Violation("A000", "file.py", 1, 1, "error text", "line"),
|
||||||
)
|
)
|
||||||
== ""
|
== ""
|
||||||
)
|
)
|
||||||
|
|
@ -70,7 +70,7 @@ def test_show_source_returns_nothing_when_there_is_source():
|
||||||
formatter = base.BaseFormatter(options(show_source=True))
|
formatter = base.BaseFormatter(options(show_source=True))
|
||||||
assert (
|
assert (
|
||||||
formatter.show_source(
|
formatter.show_source(
|
||||||
Violation("A000", "file.py", 1, 1, "error text", None)
|
Violation("A000", "file.py", 1, 1, "error text", None),
|
||||||
)
|
)
|
||||||
== ""
|
== ""
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,11 @@ def test_oserrors_are_reraised():
|
||||||
err = OSError(errno.EAGAIN, "Ominous message")
|
err = OSError(errno.EAGAIN, "Ominous message")
|
||||||
with mock.patch("_multiprocessing.SemLock", side_effect=err):
|
with mock.patch("_multiprocessing.SemLock", side_effect=err):
|
||||||
manager = _parallel_checker_manager()
|
manager = _parallel_checker_manager()
|
||||||
with mock.patch.object(manager, "run_serial") as serial:
|
with (
|
||||||
with pytest.raises(OSError):
|
mock.patch.object(manager, "run_serial") as serial,
|
||||||
manager.run()
|
pytest.raises(OSError),
|
||||||
|
):
|
||||||
|
manager.run()
|
||||||
assert serial.call_count == 0
|
assert serial.call_count == 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ def test_debug_information():
|
||||||
pkg,
|
pkg,
|
||||||
version,
|
version,
|
||||||
importlib.metadata.EntryPoint(
|
importlib.metadata.EntryPoint(
|
||||||
ep_name, "dne:dne", "flake8.extension"
|
ep_name, "dne:dne", "flake8.extension",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ def create_options(**kwargs):
|
||||||
def test_was_ignored_ignores_errors(ignore_list, extend_ignore, error_code):
|
def test_was_ignored_ignores_errors(ignore_list, extend_ignore, error_code):
|
||||||
"""Verify we detect users explicitly ignoring an error."""
|
"""Verify we detect users explicitly ignoring an error."""
|
||||||
decider = style_guide.DecisionEngine(
|
decider = style_guide.DecisionEngine(
|
||||||
create_options(ignore=ignore_list, extend_ignore=extend_ignore)
|
create_options(ignore=ignore_list, extend_ignore=extend_ignore),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert decider.was_ignored(error_code) is style_guide.Ignored.Explicitly
|
assert decider.was_ignored(error_code) is style_guide.Ignored.Explicitly
|
||||||
|
|
@ -53,11 +53,11 @@ def test_was_ignored_ignores_errors(ignore_list, extend_ignore, error_code):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_was_ignored_implicitly_selects_errors(
|
def test_was_ignored_implicitly_selects_errors(
|
||||||
ignore_list, extend_ignore, error_code
|
ignore_list, extend_ignore, error_code,
|
||||||
):
|
):
|
||||||
"""Verify we detect users does not explicitly ignore an error."""
|
"""Verify we detect users does not explicitly ignore an error."""
|
||||||
decider = style_guide.DecisionEngine(
|
decider = style_guide.DecisionEngine(
|
||||||
create_options(ignore=ignore_list, extend_ignore=extend_ignore)
|
create_options(ignore=ignore_list, extend_ignore=extend_ignore),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert decider.was_ignored(error_code) is style_guide.Selected.Implicitly
|
assert decider.was_ignored(error_code) is style_guide.Selected.Implicitly
|
||||||
|
|
@ -179,7 +179,7 @@ def test_was_selected_excludes_errors(select_list, error_code):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_decision_for(
|
def test_decision_for(
|
||||||
select_list, ignore_list, extend_ignore, error_code, expected
|
select_list, ignore_list, extend_ignore, error_code, expected,
|
||||||
):
|
):
|
||||||
"""Verify we decide when to report an error."""
|
"""Verify we decide when to report an error."""
|
||||||
decider = style_guide.DecisionEngine(
|
decider = style_guide.DecisionEngine(
|
||||||
|
|
@ -187,7 +187,7 @@ def test_decision_for(
|
||||||
select=select_list,
|
select=select_list,
|
||||||
ignore=ignore_list,
|
ignore=ignore_list,
|
||||||
extend_ignore=extend_ignore,
|
extend_ignore=extend_ignore,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert decider.decision_for(error_code) is expected
|
assert decider.decision_for(error_code) is expected
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ def test_filenames_from_a_directory_with_a_predicate():
|
||||||
_filenames_from(
|
_filenames_from(
|
||||||
arg=_normpath("a/b/"),
|
arg=_normpath("a/b/"),
|
||||||
predicate=lambda path: path.endswith(_normpath("b/c.py")),
|
predicate=lambda path: path.endswith(_normpath("b/c.py")),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
# should not include c.py
|
# should not include c.py
|
||||||
expected = _normpaths(("a/b/d.py", "a/b/e/f.py"))
|
expected = _normpaths(("a/b/d.py", "a/b/e/f.py"))
|
||||||
|
|
@ -61,7 +61,7 @@ def test_filenames_from_a_directory_with_a_predicate_from_the_current_dir():
|
||||||
_filenames_from(
|
_filenames_from(
|
||||||
arg=_normpath("./a/b"),
|
arg=_normpath("./a/b"),
|
||||||
predicate=lambda path: path == "c.py",
|
predicate=lambda path: path == "c.py",
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
# none should have matched the predicate so all returned
|
# none should have matched the predicate so all returned
|
||||||
expected = _normpaths(("./a/b/c.py", "./a/b/d.py", "./a/b/e/f.py"))
|
expected = _normpaths(("./a/b/c.py", "./a/b/d.py", "./a/b/e/f.py"))
|
||||||
|
|
@ -132,7 +132,7 @@ def _expand_paths(
|
||||||
stdin_display_name=stdin_display_name,
|
stdin_display_name=stdin_display_name,
|
||||||
filename_patterns=filename_patterns,
|
filename_patterns=filename_patterns,
|
||||||
exclude=exclude,
|
exclude=exclude,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ def _lines_from_file(tmpdir, contents, options):
|
||||||
def test_read_lines_universal_newlines(tmpdir, default_options):
|
def test_read_lines_universal_newlines(tmpdir, default_options):
|
||||||
r"""Verify that line endings are translated to \n."""
|
r"""Verify that line endings are translated to \n."""
|
||||||
lines = _lines_from_file(
|
lines = _lines_from_file(
|
||||||
tmpdir, b"# coding: utf-8\r\nx = 1\r\n", default_options
|
tmpdir, b"# coding: utf-8\r\nx = 1\r\n", default_options,
|
||||||
)
|
)
|
||||||
assert lines == ["# coding: utf-8\n", "x = 1\n"]
|
assert lines == ["# coding: utf-8\n", "x = 1\n"]
|
||||||
|
|
||||||
|
|
@ -36,7 +36,7 @@ def test_read_lines_universal_newlines(tmpdir, default_options):
|
||||||
def test_read_lines_incorrect_utf_16(tmpdir, default_options):
|
def test_read_lines_incorrect_utf_16(tmpdir, default_options):
|
||||||
"""Verify that an incorrectly encoded file is read as latin-1."""
|
"""Verify that an incorrectly encoded file is read as latin-1."""
|
||||||
lines = _lines_from_file(
|
lines = _lines_from_file(
|
||||||
tmpdir, b"# coding: utf16\nx = 1\n", default_options
|
tmpdir, b"# coding: utf16\nx = 1\n", default_options,
|
||||||
)
|
)
|
||||||
assert lines == ["# coding: utf16\n", "x = 1\n"]
|
assert lines == ["# coding: utf16\n", "x = 1\n"]
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ def test_read_lines_incorrect_utf_16(tmpdir, default_options):
|
||||||
def test_read_lines_unknown_encoding(tmpdir, default_options):
|
def test_read_lines_unknown_encoding(tmpdir, default_options):
|
||||||
"""Verify that an unknown encoding is still read as latin-1."""
|
"""Verify that an unknown encoding is still read as latin-1."""
|
||||||
lines = _lines_from_file(
|
lines = _lines_from_file(
|
||||||
tmpdir, b"# coding: fake-encoding\nx = 1\n", default_options
|
tmpdir, b"# coding: fake-encoding\nx = 1\n", default_options,
|
||||||
)
|
)
|
||||||
assert lines == ["# coding: fake-encoding\n", "x = 1\n"]
|
assert lines == ["# coding: fake-encoding\n", "x = 1\n"]
|
||||||
|
|
||||||
|
|
@ -289,7 +289,7 @@ def test_processor_split_line(default_options):
|
||||||
def test_build_ast(default_options):
|
def test_build_ast(default_options):
|
||||||
"""Verify the logic for how we build an AST for plugins."""
|
"""Verify the logic for how we build an AST for plugins."""
|
||||||
file_processor = processor.FileProcessor(
|
file_processor = processor.FileProcessor(
|
||||||
"-", default_options, lines=["a = 1\n"]
|
"-", default_options, lines=["a = 1\n"],
|
||||||
)
|
)
|
||||||
|
|
||||||
module = file_processor.build_ast()
|
module = file_processor.build_ast()
|
||||||
|
|
@ -299,7 +299,7 @@ def test_build_ast(default_options):
|
||||||
def test_next_logical_line_updates_the_previous_logical_line(default_options):
|
def test_next_logical_line_updates_the_previous_logical_line(default_options):
|
||||||
"""Verify that we update our tracking of the previous logical line."""
|
"""Verify that we update our tracking of the previous logical line."""
|
||||||
file_processor = processor.FileProcessor(
|
file_processor = processor.FileProcessor(
|
||||||
"-", default_options, lines=["a = 1\n"]
|
"-", default_options, lines=["a = 1\n"],
|
||||||
)
|
)
|
||||||
|
|
||||||
file_processor.indent_level = 1
|
file_processor.indent_level = 1
|
||||||
|
|
@ -315,7 +315,7 @@ def test_next_logical_line_updates_the_previous_logical_line(default_options):
|
||||||
def test_visited_new_blank_line(default_options):
|
def test_visited_new_blank_line(default_options):
|
||||||
"""Verify we update the number of blank lines seen."""
|
"""Verify we update the number of blank lines seen."""
|
||||||
file_processor = processor.FileProcessor(
|
file_processor = processor.FileProcessor(
|
||||||
"-", default_options, lines=["a = 1\n"]
|
"-", default_options, lines=["a = 1\n"],
|
||||||
)
|
)
|
||||||
|
|
||||||
assert file_processor.blank_lines == 0
|
assert file_processor.blank_lines == 0
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from flake8.main import options
|
||||||
def test_stage1_arg_parser():
|
def test_stage1_arg_parser():
|
||||||
stage1_parser = options.stage1_arg_parser()
|
stage1_parser = options.stage1_arg_parser()
|
||||||
opts, args = stage1_parser.parse_known_args(
|
opts, args = stage1_parser.parse_known_args(
|
||||||
["--foo", "--verbose", "src", "setup.py", "--statistics", "--version"]
|
["--foo", "--verbose", "src", "setup.py", "--statistics", "--version"],
|
||||||
)
|
)
|
||||||
|
|
||||||
assert opts.verbose
|
assert opts.verbose
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ def test_parse_args_handles_comma_separated_defaults(optmanager):
|
||||||
assert optmanager.config_options_dict == {}
|
assert optmanager.config_options_dict == {}
|
||||||
|
|
||||||
optmanager.add_option(
|
optmanager.add_option(
|
||||||
"--exclude", default="E123,W234", comma_separated_list=True
|
"--exclude", default="E123,W234", comma_separated_list=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
options = optmanager.parse_args([])
|
options = optmanager.parse_args([])
|
||||||
|
|
@ -135,7 +135,7 @@ def test_parse_args_handles_comma_separated_lists(optmanager):
|
||||||
assert optmanager.config_options_dict == {}
|
assert optmanager.config_options_dict == {}
|
||||||
|
|
||||||
optmanager.add_option(
|
optmanager.add_option(
|
||||||
"--exclude", default="E123,W234", comma_separated_list=True
|
"--exclude", default="E123,W234", comma_separated_list=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
options = optmanager.parse_args(["--exclude", "E201,W111,F280"])
|
options = optmanager.parse_args(["--exclude", "E201,W111,F280"])
|
||||||
|
|
@ -148,11 +148,11 @@ def test_parse_args_normalize_paths(optmanager):
|
||||||
assert optmanager.config_options_dict == {}
|
assert optmanager.config_options_dict == {}
|
||||||
|
|
||||||
optmanager.add_option(
|
optmanager.add_option(
|
||||||
"--extra-config", normalize_paths=True, comma_separated_list=True
|
"--extra-config", normalize_paths=True, comma_separated_list=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
options = optmanager.parse_args(
|
options = optmanager.parse_args(
|
||||||
["--extra-config", "../config.ini,tox.ini,flake8/some-other.cfg"]
|
["--extra-config", "../config.ini,tox.ini,flake8/some-other.cfg"],
|
||||||
)
|
)
|
||||||
assert options.extra_config == [
|
assert options.extra_config == [
|
||||||
os.path.abspath("../config.ini"),
|
os.path.abspath("../config.ini"),
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ def test_load_extra_config_utf8(tmpdir):
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def opt_manager():
|
def opt_manager():
|
||||||
ret = OptionManager(
|
ret = OptionManager(
|
||||||
version="123", plugin_versions="", parents=[], formatter_names=[]
|
version="123", plugin_versions="", parents=[], formatter_names=[],
|
||||||
)
|
)
|
||||||
register_default_options(ret)
|
register_default_options(ret)
|
||||||
return ret
|
return ret
|
||||||
|
|
@ -213,7 +213,7 @@ def test_parse_config_ignores_unknowns(tmp_path, opt_manager, caplog):
|
||||||
"flake8.options.config",
|
"flake8.options.config",
|
||||||
10,
|
10,
|
||||||
'Option "wat" is not registered. Ignoring.',
|
'Option "wat" is not registered. Ignoring.',
|
||||||
)
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ def test_handle_error_does_not_raise_type_errors():
|
||||||
)
|
)
|
||||||
|
|
||||||
assert 1 == guide.handle_error(
|
assert 1 == guide.handle_error(
|
||||||
"T111", "file.py", 1, 1, "error found", "a = 1"
|
"T111", "file.py", 1, 1, "error found", "a = 1",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -110,7 +110,7 @@ def test_style_guide_manager_pre_file_ignores_parsing():
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_style_guide_manager_pre_file_ignores(
|
def test_style_guide_manager_pre_file_ignores(
|
||||||
ignores, violation, filename, handle_error_return
|
ignores, violation, filename, handle_error_return,
|
||||||
):
|
):
|
||||||
"""Verify how the StyleGuideManager creates a default style guide."""
|
"""Verify how the StyleGuideManager creates a default style guide."""
|
||||||
formatter = mock.create_autospec(base.BaseFormatter, instance=True)
|
formatter = mock.create_autospec(base.BaseFormatter, instance=True)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue