mirror of
https://github.com/PyCQA/flake8.git
synced 2026-03-29 10:36:53 +00:00
require python>=3.7
This commit is contained in:
parent
6027577d32
commit
e94fb10940
76 changed files with 337 additions and 263 deletions
5
.github/workflows/main.yml
vendored
5
.github/workflows/main.yml
vendored
|
|
@ -15,9 +15,6 @@ jobs:
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
python: pypy-3.7
|
python: pypy-3.7
|
||||||
toxenv: py
|
toxenv: py
|
||||||
- os: ubuntu-latest
|
|
||||||
python: 3.6
|
|
||||||
toxenv: py
|
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
python: 3.7
|
python: 3.7
|
||||||
toxenv: py
|
toxenv: py
|
||||||
|
|
@ -32,7 +29,7 @@ jobs:
|
||||||
toxenv: py
|
toxenv: py
|
||||||
# windows
|
# windows
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python: 3.6
|
python: 3.7
|
||||||
toxenv: py
|
toxenv: py
|
||||||
# misc
|
# misc
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,16 @@ repos:
|
||||||
rev: v3.8.2
|
rev: v3.8.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: reorder-python-imports
|
- id: reorder-python-imports
|
||||||
args: [--application-directories, '.:src', --py36-plus]
|
args: [
|
||||||
|
--application-directories, '.:src',
|
||||||
|
--py37-plus,
|
||||||
|
--add-import, 'from __future__ import annotations',
|
||||||
|
]
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v2.37.3
|
rev: v2.37.3
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py36-plus]
|
args: [--py37-plus]
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 22.6.0
|
rev: 22.6.0
|
||||||
hooks:
|
hooks:
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import os.path
|
import os.path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pycodestyle
|
import pycodestyle
|
||||||
|
|
||||||
|
|
@ -20,7 +21,7 @@ def _too_long(s: str) -> str:
|
||||||
class Call(NamedTuple):
|
class Call(NamedTuple):
|
||||||
name: str
|
name: str
|
||||||
is_generator: bool
|
is_generator: bool
|
||||||
params: Tuple[str, ...]
|
params: tuple[str, ...]
|
||||||
|
|
||||||
def to_src(self) -> str:
|
def to_src(self) -> str:
|
||||||
params_s = ", ".join(self.params)
|
params_s = ", ".join(self.params)
|
||||||
|
|
@ -35,7 +36,7 @@ class Call(NamedTuple):
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_func(cls, func: Callable[..., Any]) -> "Call":
|
def from_func(cls, func: Callable[..., Any]) -> Call:
|
||||||
spec = inspect.getfullargspec(func)
|
spec = inspect.getfullargspec(func)
|
||||||
params = tuple(spec.args)
|
params = tuple(spec.args)
|
||||||
return cls(func.__name__, inspect.isgeneratorfunction(func), params)
|
return cls(func.__name__, inspect.isgeneratorfunction(func), params)
|
||||||
|
|
@ -55,9 +56,10 @@ def lines() -> Generator[str, None, None]:
|
||||||
|
|
||||||
yield f'"""Generated using ./bin/{os.path.basename(__file__)}."""'
|
yield f'"""Generated using ./bin/{os.path.basename(__file__)}."""'
|
||||||
yield "# fmt: off"
|
yield "# fmt: off"
|
||||||
|
yield "from __future__ import annotations"
|
||||||
|
yield ""
|
||||||
yield "from typing import Any"
|
yield "from typing import Any"
|
||||||
yield "from typing import Generator"
|
yield "from typing import Generator"
|
||||||
yield "from typing import Tuple"
|
|
||||||
yield ""
|
yield ""
|
||||||
imports = sorted(call.name for call in logical + physical)
|
imports = sorted(call.name for call in logical + physical)
|
||||||
for name in imports:
|
for name in imports:
|
||||||
|
|
@ -69,7 +71,7 @@ def lines() -> Generator[str, None, None]:
|
||||||
logical_params = {param for call in logical for param in call.params}
|
logical_params = {param for call in logical for param in call.params}
|
||||||
for param in sorted(logical_params):
|
for param in sorted(logical_params):
|
||||||
yield f" {param}: Any,"
|
yield f" {param}: Any,"
|
||||||
yield ") -> Generator[Tuple[int, str], None, None]:"
|
yield ") -> Generator[tuple[int, str], None, None]:"
|
||||||
yield ' """Run pycodestyle logical checks."""'
|
yield ' """Run pycodestyle logical checks."""'
|
||||||
for call in sorted(logical):
|
for call in sorted(logical):
|
||||||
yield call.to_src()
|
yield call.to_src()
|
||||||
|
|
@ -80,7 +82,7 @@ def lines() -> Generator[str, None, None]:
|
||||||
physical_params = {param for call in physical for param in call.params}
|
physical_params = {param for call in physical for param in call.params}
|
||||||
for param in sorted(physical_params):
|
for param in sorted(physical_params):
|
||||||
yield f" {param}: Any,"
|
yield f" {param}: Any,"
|
||||||
yield ") -> Generator[Tuple[int, str], None, None]:"
|
yield ") -> Generator[tuple[int, str], None, None]:"
|
||||||
yield ' """Run pycodestyle physical checks."""'
|
yield ' """Run pycodestyle physical checks."""'
|
||||||
for call in sorted(physical):
|
for call in sorted(physical):
|
||||||
yield call.to_src()
|
yield call.to_src()
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
# 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
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import flake8
|
import flake8
|
||||||
|
|
||||||
# -- General configuration ------------------------------------------------
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import setuptools
|
import setuptools
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Module for an example Flake8 plugin."""
|
"""Module for an example Flake8 plugin."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from .off_by_default import ExampleTwo
|
from .off_by_default import ExampleTwo
|
||||||
from .on_by_default import ExampleOne
|
from .on_by_default import ExampleOne
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Our first example plugin."""
|
"""Our first example plugin."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
class ExampleTwo:
|
class ExampleTwo:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Our first example plugin."""
|
"""Our first example plugin."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
class ExampleOne:
|
class ExampleOne:
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ classifiers =
|
||||||
Programming Language :: Python
|
Programming Language :: Python
|
||||||
Programming Language :: Python :: 3
|
Programming Language :: Python :: 3
|
||||||
Programming Language :: Python :: 3 :: Only
|
Programming Language :: Python :: 3 :: Only
|
||||||
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
|
||||||
Programming Language :: Python :: 3.9
|
Programming Language :: Python :: 3.9
|
||||||
|
|
@ -43,7 +42,7 @@ install_requires =
|
||||||
pycodestyle>=2.9.0,<2.10.0
|
pycodestyle>=2.9.0,<2.10.0
|
||||||
pyflakes>=2.5.0,<2.6.0
|
pyflakes>=2.5.0,<2.6.0
|
||||||
importlib-metadata>=1.1.0,<4.3;python_version<"3.8"
|
importlib-metadata>=1.1.0,<4.3;python_version<"3.8"
|
||||||
python_requires = >=3.6.1
|
python_requires = >=3.7
|
||||||
|
|
||||||
[options.packages.find]
|
[options.packages.find]
|
||||||
where = src
|
where = src
|
||||||
|
|
|
||||||
2
setup.py
2
setup.py
|
|
@ -1,4 +1,6 @@
|
||||||
"""Packaging logic for Flake8."""
|
"""Packaging logic for Flake8."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ This module
|
||||||
.. autofunction:: flake8.configure_logging
|
.. autofunction:: flake8.configure_logging
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
|
||||||
from typing import Type
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
LOG.addHandler(logging.NullHandler())
|
LOG.addHandler(logging.NullHandler())
|
||||||
|
|
@ -35,7 +35,7 @@ LOG_FORMAT = (
|
||||||
|
|
||||||
def configure_logging(
|
def configure_logging(
|
||||||
verbosity: int,
|
verbosity: int,
|
||||||
filename: Optional[str] = None,
|
filename: str | None = None,
|
||||||
logformat: str = LOG_FORMAT,
|
logformat: str = LOG_FORMAT,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Configure logging for flake8.
|
"""Configure logging for flake8.
|
||||||
|
|
@ -56,7 +56,7 @@ def configure_logging(
|
||||||
|
|
||||||
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: Type[logging.Handler] = logging.StreamHandler
|
handler_cls: type[logging.Handler] = logging.StreamHandler
|
||||||
else:
|
else:
|
||||||
fileobj = filename
|
fileobj = filename
|
||||||
handler_cls = logging.FileHandler
|
handler_cls = logging.FileHandler
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Module allowing for ``python -m flake8 ...``."""
|
"""Module allowing for ``python -m flake8 ...``."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from flake8.main.cli import main
|
from flake8.main.cli import main
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Expose backports in a single place."""
|
"""Expose backports in a single place."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if sys.version_info >= (3, 8): # pragma: no cover (PY38+)
|
if sys.version_info >= (3, 8): # pragma: no cover (PY38+)
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,4 @@
|
||||||
This is the only submodule in Flake8 with a guaranteed stable API. All other
|
This is the only submodule in Flake8 with a guaranteed stable API. All other
|
||||||
submodules are considered internal only and are subject to change.
|
submodules are considered internal only and are subject to change.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,12 @@
|
||||||
Previously, users would import :func:`get_style_guide` from ``flake8.engine``.
|
Previously, users would import :func:`get_style_guide` from ``flake8.engine``.
|
||||||
In 3.0 we no longer have an "engine" module but we maintain the API from it.
|
In 3.0 we no longer have an "engine" module but we maintain the API from it.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import List
|
|
||||||
from typing import Optional
|
|
||||||
from typing import Type
|
|
||||||
|
|
||||||
import flake8
|
import flake8
|
||||||
from flake8.discover_files import expand_paths
|
from flake8.discover_files import expand_paths
|
||||||
|
|
@ -53,7 +52,7 @@ class Report:
|
||||||
"""Return the total number of errors."""
|
"""Return the total number of errors."""
|
||||||
return self._application.result_count
|
return self._application.result_count
|
||||||
|
|
||||||
def get_statistics(self, violation: str) -> List[str]:
|
def get_statistics(self, violation: str) -> list[str]:
|
||||||
"""Get the list of occurrences of a violation.
|
"""Get the list of occurrences of a violation.
|
||||||
|
|
||||||
:returns:
|
:returns:
|
||||||
|
|
@ -97,12 +96,12 @@ class StyleGuide:
|
||||||
return self._application.options
|
return self._application.options
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def paths(self) -> List[str]:
|
def paths(self) -> list[str]:
|
||||||
"""Return the extra arguments passed as paths."""
|
"""Return the extra arguments passed as paths."""
|
||||||
assert self._application.options is not None
|
assert self._application.options is not None
|
||||||
return self._application.options.filenames
|
return self._application.options.filenames
|
||||||
|
|
||||||
def check_files(self, paths: Optional[List[str]] = None) -> Report:
|
def check_files(self, paths: list[str] | None = None) -> Report:
|
||||||
"""Run collected checks on the files provided.
|
"""Run collected checks on the files provided.
|
||||||
|
|
||||||
This will check the files passed in and return a :class:`Report`
|
This will check the files passed in and return a :class:`Report`
|
||||||
|
|
@ -119,7 +118,7 @@ class StyleGuide:
|
||||||
self._application.report_errors()
|
self._application.report_errors()
|
||||||
return Report(self._application)
|
return Report(self._application)
|
||||||
|
|
||||||
def excluded(self, filename: str, parent: Optional[str] = None) -> bool:
|
def excluded(self, filename: str, parent: str | None = None) -> bool:
|
||||||
"""Determine if a file is excluded.
|
"""Determine if a file is excluded.
|
||||||
|
|
||||||
:param filename:
|
:param filename:
|
||||||
|
|
@ -148,7 +147,7 @@ class StyleGuide:
|
||||||
|
|
||||||
def init_report(
|
def init_report(
|
||||||
self,
|
self,
|
||||||
reporter: Optional[Type[formatter.BaseFormatter]] = None,
|
reporter: type[formatter.BaseFormatter] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up a formatter for this run of Flake8."""
|
"""Set up a formatter for this run of Flake8."""
|
||||||
if reporter is None:
|
if reporter is None:
|
||||||
|
|
@ -170,9 +169,9 @@ class StyleGuide:
|
||||||
def input_file(
|
def input_file(
|
||||||
self,
|
self,
|
||||||
filename: str,
|
filename: str,
|
||||||
lines: Optional[Any] = None,
|
lines: Any | None = None,
|
||||||
expected: Optional[Any] = None,
|
expected: Any | None = None,
|
||||||
line_offset: Optional[Any] = 0,
|
line_offset: Any | None = 0,
|
||||||
) -> Report:
|
) -> Report:
|
||||||
"""Run collected checks on a single file.
|
"""Run collected checks on a single file.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Checker Manager and Checker classes."""
|
"""Checker Manager and Checker classes."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import collections
|
import collections
|
||||||
import errno
|
import errno
|
||||||
|
|
@ -8,7 +10,6 @@ import multiprocessing.pool
|
||||||
import signal
|
import signal
|
||||||
import tokenize
|
import tokenize
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
@ -71,8 +72,8 @@ class Manager:
|
||||||
self.options = style_guide.options
|
self.options = style_guide.options
|
||||||
self.plugins = plugins
|
self.plugins = plugins
|
||||||
self.jobs = self._job_count()
|
self.jobs = self._job_count()
|
||||||
self._all_checkers: List[FileChecker] = []
|
self._all_checkers: list[FileChecker] = []
|
||||||
self.checkers: List[FileChecker] = []
|
self.checkers: list[FileChecker] = []
|
||||||
self.statistics = {
|
self.statistics = {
|
||||||
"files": 0,
|
"files": 0,
|
||||||
"logical lines": 0,
|
"logical lines": 0,
|
||||||
|
|
@ -152,7 +153,7 @@ class Manager:
|
||||||
)
|
)
|
||||||
return reported_results_count
|
return reported_results_count
|
||||||
|
|
||||||
def make_checkers(self, paths: Optional[List[str]] = None) -> None:
|
def make_checkers(self, paths: list[str] | None = None) -> None:
|
||||||
"""Create checkers for each file."""
|
"""Create checkers for each file."""
|
||||||
if paths is None:
|
if paths is None:
|
||||||
paths = self.options.filenames
|
paths = self.options.filenames
|
||||||
|
|
@ -174,7 +175,7 @@ class Manager:
|
||||||
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) -> Tuple[int, int]:
|
def report(self) -> 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
|
||||||
|
|
@ -195,8 +196,8 @@ class Manager:
|
||||||
def run_parallel(self) -> None:
|
def run_parallel(self) -> None:
|
||||||
"""Run the checkers in parallel."""
|
"""Run the checkers in parallel."""
|
||||||
# fmt: off
|
# fmt: off
|
||||||
final_results: Dict[str, List[Tuple[str, int, int, str, Optional[str]]]] = collections.defaultdict(list) # noqa: E501
|
final_results: dict[str, list[tuple[str, int, int, str, str | None]]] = collections.defaultdict(list) # noqa: E501
|
||||||
final_statistics: Dict[str, Dict[str, int]] = collections.defaultdict(dict) # 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)
|
||||||
|
|
@ -254,7 +255,7 @@ class Manager:
|
||||||
LOG.warning("Flake8 was interrupted by the user")
|
LOG.warning("Flake8 was interrupted by the user")
|
||||||
raise exceptions.EarlyQuit("Early quit while running checks")
|
raise exceptions.EarlyQuit("Early quit while running checks")
|
||||||
|
|
||||||
def start(self, paths: Optional[List[str]] = None) -> None:
|
def start(self, paths: list[str] | None = None) -> None:
|
||||||
"""Start checking files.
|
"""Start checking files.
|
||||||
|
|
||||||
:param paths:
|
:param paths:
|
||||||
|
|
@ -301,7 +302,7 @@ class FileChecker:
|
||||||
"""Provide helpful debugging representation."""
|
"""Provide helpful debugging representation."""
|
||||||
return f"FileChecker for {self.filename}"
|
return f"FileChecker for {self.filename}"
|
||||||
|
|
||||||
def _make_processor(self) -> Optional[processor.FileProcessor]:
|
def _make_processor(self) -> processor.FileProcessor | None:
|
||||||
try:
|
try:
|
||||||
return processor.FileProcessor(self.filename, self.options)
|
return processor.FileProcessor(self.filename, self.options)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
|
|
@ -316,7 +317,7 @@ class FileChecker:
|
||||||
|
|
||||||
def report(
|
def report(
|
||||||
self,
|
self,
|
||||||
error_code: Optional[str],
|
error_code: str | None,
|
||||||
line_number: int,
|
line_number: int,
|
||||||
column: int,
|
column: int,
|
||||||
text: str,
|
text: str,
|
||||||
|
|
@ -361,7 +362,7 @@ class FileChecker:
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extract_syntax_information(exception: Exception) -> Tuple[int, int]:
|
def _extract_syntax_information(exception: Exception) -> tuple[int, int]:
|
||||||
if (
|
if (
|
||||||
len(exception.args) > 1
|
len(exception.args) > 1
|
||||||
and exception.args[1]
|
and exception.args[1]
|
||||||
|
|
@ -524,7 +525,7 @@ class FileChecker:
|
||||||
self.run_physical_checks(file_processor.lines[-1])
|
self.run_physical_checks(file_processor.lines[-1])
|
||||||
self.run_logical_checks()
|
self.run_logical_checks()
|
||||||
|
|
||||||
def run_checks(self) -> Tuple[str, Results, Dict[str, int]]:
|
def run_checks(self) -> tuple[str, Results, dict[str, int]]:
|
||||||
"""Run checks against the file."""
|
"""Run checks against the file."""
|
||||||
assert self.processor is not None
|
assert self.processor is not None
|
||||||
try:
|
try:
|
||||||
|
|
@ -592,7 +593,7 @@ def _pool_init() -> None:
|
||||||
|
|
||||||
def _try_initialize_processpool(
|
def _try_initialize_processpool(
|
||||||
job_count: int,
|
job_count: int,
|
||||||
) -> Optional[multiprocessing.pool.Pool]:
|
) -> multiprocessing.pool.Pool | None:
|
||||||
"""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)
|
||||||
|
|
@ -617,13 +618,13 @@ def calculate_pool_chunksize(num_checkers: int, num_jobs: int) -> int:
|
||||||
return max(num_checkers // (num_jobs * 2), 1)
|
return max(num_checkers // (num_jobs * 2), 1)
|
||||||
|
|
||||||
|
|
||||||
def _run_checks(checker: FileChecker) -> Tuple[str, Results, Dict[str, int]]:
|
def _run_checks(checker: FileChecker) -> tuple[str, Results, dict[str, int]]:
|
||||||
return checker.run_checks()
|
return checker.run_checks()
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
return offset
|
return offset
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Constants that define defaults."""
|
"""Constants that define defaults."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
EXCLUDE = (
|
EXCLUDE = (
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Functions related to discovering paths."""
|
"""Functions related to discovering paths."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Exception classes for all of Flake8."""
|
"""Exception classes for all of Flake8."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
class Flake8Exception(Exception):
|
class Flake8Exception(Exception):
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
"""Submodule containing the default formatters for Flake8."""
|
"""Submodule containing the default formatters for Flake8."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
See: https://github.com/pre-commit/pre-commit/blob/cb40e96/pre_commit/color.py
|
See: https://github.com/pre-commit/pre-commit/blob/cb40e96/pre_commit/color.py
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if sys.platform == "win32": # pragma: no cover (windows)
|
if sys.platform == "win32": # pragma: no cover (windows)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
"""The base class and interface for all formatting plugins."""
|
"""The base class and interface for all formatting plugins."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from typing import IO
|
from typing import IO
|
||||||
from typing import List
|
|
||||||
from typing import Optional
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from flake8.formatting import _windows_color
|
from flake8.formatting import _windows_color
|
||||||
from flake8.statistics import Statistics
|
from flake8.statistics import Statistics
|
||||||
|
|
@ -46,7 +45,7 @@ class BaseFormatter:
|
||||||
"""
|
"""
|
||||||
self.options = options
|
self.options = options
|
||||||
self.filename = options.output_file
|
self.filename = options.output_file
|
||||||
self.output_fd: Optional[IO[str]] = None
|
self.output_fd: IO[str] | None = None
|
||||||
self.newline = "\n"
|
self.newline = "\n"
|
||||||
self.color = options.color == "always" or (
|
self.color = options.color == "always" or (
|
||||||
options.color == "auto"
|
options.color == "auto"
|
||||||
|
|
@ -84,7 +83,7 @@ class BaseFormatter:
|
||||||
os.makedirs(dirname, exist_ok=True)
|
os.makedirs(dirname, exist_ok=True)
|
||||||
self.output_fd = open(self.filename, "a")
|
self.output_fd = open(self.filename, "a")
|
||||||
|
|
||||||
def handle(self, error: "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
|
||||||
|
|
@ -99,7 +98,7 @@ class BaseFormatter:
|
||||||
source = self.show_source(error)
|
source = self.show_source(error)
|
||||||
self.write(line, source)
|
self.write(line, source)
|
||||||
|
|
||||||
def format(self, error: "Violation") -> Optional[str]:
|
def format(self, error: Violation) -> str | None:
|
||||||
"""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.
|
||||||
|
|
@ -114,7 +113,7 @@ class BaseFormatter:
|
||||||
"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:
|
||||||
"""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)
|
||||||
|
|
@ -123,7 +122,7 @@ class BaseFormatter:
|
||||||
count += sum(stat.count for stat in stats_for_error_code)
|
count += sum(stat.count for stat in stats_for_error_code)
|
||||||
self._write(f"{count:<5} {error_code} {statistic.message}")
|
self._write(f"{count:<5} {error_code} {statistic.message}")
|
||||||
|
|
||||||
def show_benchmarks(self, benchmarks: List[Tuple[str, float]]) -> None:
|
def show_benchmarks(self, benchmarks: 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:
|
||||||
|
|
@ -144,7 +143,7 @@ class BaseFormatter:
|
||||||
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: "Violation") -> Optional[str]:
|
def show_source(self, error: Violation) -> str | None:
|
||||||
"""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
|
||||||
|
|
@ -178,7 +177,7 @@ class BaseFormatter:
|
||||||
if self.output_fd is None or self.options.tee:
|
if self.output_fd is None or self.options.tee:
|
||||||
sys.stdout.buffer.write(output.encode() + self.newline.encode())
|
sys.stdout.buffer.write(output.encode() + self.newline.encode())
|
||||||
|
|
||||||
def write(self, line: Optional[str], source: Optional[str]) -> None:
|
def write(self, line: str | None, source: str | None) -> 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
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
"""Default formatting class for Flake8."""
|
"""Default formatting class for Flake8."""
|
||||||
from typing import Optional
|
from __future__ import annotations
|
||||||
from typing import Set
|
|
||||||
|
|
||||||
from flake8.formatting import base
|
from flake8.formatting import base
|
||||||
from flake8.violation import Violation
|
from flake8.violation import Violation
|
||||||
|
|
@ -38,7 +37,7 @@ class SimpleFormatter(base.BaseFormatter):
|
||||||
|
|
||||||
error_format: str
|
error_format: str
|
||||||
|
|
||||||
def format(self, error: "Violation") -> Optional[str]:
|
def format(self, error: Violation) -> str | None:
|
||||||
"""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
|
||||||
|
|
@ -86,12 +85,12 @@ class FilenameOnly(SimpleFormatter):
|
||||||
|
|
||||||
def after_init(self) -> None:
|
def after_init(self) -> None:
|
||||||
"""Initialize our set of filenames."""
|
"""Initialize our set of filenames."""
|
||||||
self.filenames_already_printed: Set[str] = set()
|
self.filenames_already_printed: set[str] = set()
|
||||||
|
|
||||||
def show_source(self, error: "Violation") -> Optional[str]:
|
def show_source(self, error: Violation) -> str | None:
|
||||||
"""Do not include the source code."""
|
"""Do not include the source code."""
|
||||||
|
|
||||||
def format(self, error: "Violation") -> Optional[str]:
|
def format(self, error: Violation) -> str | None:
|
||||||
"""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)
|
||||||
|
|
@ -103,8 +102,8 @@ class FilenameOnly(SimpleFormatter):
|
||||||
class Nothing(base.BaseFormatter):
|
class Nothing(base.BaseFormatter):
|
||||||
"""Print absolutely nothing."""
|
"""Print absolutely nothing."""
|
||||||
|
|
||||||
def format(self, error: "Violation") -> Optional[str]:
|
def format(self, error: Violation) -> str | None:
|
||||||
"""Do nothing."""
|
"""Do nothing."""
|
||||||
|
|
||||||
def show_source(self, error: "Violation") -> Optional[str]:
|
def show_source(self, error: Violation) -> str | None:
|
||||||
"""Do not print the source."""
|
"""Do not print the source."""
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
"""Module containing the logic for the Flake8 entry-points."""
|
"""Module containing the logic for the Flake8 entry-points."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
"""Module containing the application logic for Flake8."""
|
"""Module containing the application logic for Flake8."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import configparser
|
import configparser
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
from typing import Dict
|
|
||||||
from typing import List
|
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Set
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import flake8
|
import flake8
|
||||||
from flake8 import checker
|
from flake8 import checker
|
||||||
|
|
@ -38,27 +35,27 @@ class Application:
|
||||||
#: 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: Optional[float] = None
|
self.end_time: float | None = None
|
||||||
#: The prelimary argument parser for handling options required for
|
#: The prelimary argument parser for handling options required for
|
||||||
#: obtaining and parsing the configuration file.
|
#: obtaining and parsing the configuration file.
|
||||||
self.prelim_arg_parser = options.stage1_arg_parser()
|
self.prelim_arg_parser = options.stage1_arg_parser()
|
||||||
#: The instance of :class:`flake8.options.manager.OptionManager` used
|
#: The instance of :class:`flake8.options.manager.OptionManager` used
|
||||||
#: to parse and handle the options and arguments passed by the user
|
#: to parse and handle the options and arguments passed by the user
|
||||||
self.option_manager: Optional[manager.OptionManager] = None
|
self.option_manager: manager.OptionManager | None = None
|
||||||
|
|
||||||
self.plugins: Optional[finder.Plugins] = None
|
self.plugins: finder.Plugins | None = None
|
||||||
#: The user-selected formatter from :attr:`formatting_plugins`
|
#: The user-selected formatter from :attr:`formatting_plugins`
|
||||||
self.formatter: Optional[BaseFormatter] = None
|
self.formatter: BaseFormatter | None = 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: Optional[style_guide.StyleGuideManager] = None
|
self.guide: style_guide.StyleGuideManager | None = 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: Optional[checker.Manager] = None
|
self.file_checker_manager: checker.Manager | None = 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: Optional[argparse.Namespace] = None
|
self.options: argparse.Namespace | None = 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
|
||||||
|
|
@ -70,11 +67,11 @@ class Application:
|
||||||
self.catastrophic_failure = False
|
self.catastrophic_failure = False
|
||||||
|
|
||||||
#: The parsed diff information
|
#: The parsed diff information
|
||||||
self.parsed_diff: Dict[str, Set[int]] = {}
|
self.parsed_diff: dict[str, set[int]] = {}
|
||||||
|
|
||||||
def parse_preliminary_options(
|
def parse_preliminary_options(
|
||||||
self, argv: Sequence[str]
|
self, argv: Sequence[str]
|
||||||
) -> Tuple[argparse.Namespace, 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
|
||||||
|
|
@ -111,8 +108,8 @@ class Application:
|
||||||
cfg: configparser.RawConfigParser,
|
cfg: configparser.RawConfigParser,
|
||||||
cfg_dir: str,
|
cfg_dir: str,
|
||||||
*,
|
*,
|
||||||
enable_extensions: Optional[str],
|
enable_extensions: str | None,
|
||||||
require_plugins: Optional[str],
|
require_plugins: str | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Find and load the plugins for this application.
|
"""Find and load the plugins for this application.
|
||||||
|
|
||||||
|
|
@ -143,7 +140,7 @@ class Application:
|
||||||
self,
|
self,
|
||||||
cfg: configparser.RawConfigParser,
|
cfg: configparser.RawConfigParser,
|
||||||
cfg_dir: str,
|
cfg_dir: str,
|
||||||
argv: List[str],
|
argv: list[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Parse configuration files and the CLI options."""
|
"""Parse configuration files and the CLI options."""
|
||||||
assert self.option_manager is not None
|
assert self.option_manager is not None
|
||||||
|
|
@ -218,7 +215,7 @@ class Application:
|
||||||
assert self.options is not None
|
assert self.options is not None
|
||||||
assert self.file_checker_manager is not None
|
assert self.file_checker_manager is not None
|
||||||
if self.options.diff:
|
if self.options.diff:
|
||||||
files: Optional[List[str]] = sorted(self.parsed_diff)
|
files: list[str] | None = sorted(self.parsed_diff)
|
||||||
if not files:
|
if not files:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
"""Command-line implementation of flake8."""
|
"""Command-line implementation of flake8."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
from flake8.main import application
|
from flake8.main import application
|
||||||
|
|
||||||
|
|
||||||
def main(argv: Optional[Sequence[str]] = None) -> int:
|
def main(argv: Sequence[str] | None = None) -> int:
|
||||||
"""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,12 +1,13 @@
|
||||||
"""Module containing the logic for our debugging logic."""
|
"""Module containing the logic for our debugging logic."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import platform
|
import platform
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
from flake8.plugins.finder import Plugins
|
from flake8.plugins.finder import Plugins
|
||||||
|
|
||||||
|
|
||||||
def information(version: str, plugins: Plugins) -> Dict[str, Any]:
|
def information(version: str, plugins: Plugins) -> dict[str, Any]:
|
||||||
"""Generate the information to be printed for the bug report."""
|
"""Generate the information to be printed for the bug report."""
|
||||||
versions = sorted(
|
versions = sorted(
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Contains the logic for all of the default options for Flake8."""
|
"""Contains the logic for all of the default options for Flake8."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from flake8 import defaults
|
from flake8 import defaults
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,4 @@
|
||||||
to aggregate configuration into one object used by plugins and Flake8.
|
to aggregate configuration into one object used by plugins and Flake8.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,11 @@
|
||||||
This holds the logic that uses the collected and merged config files and
|
This holds the logic that uses the collected and merged config files and
|
||||||
applies the user-specified command-line configuration on top of it.
|
applies the user-specified command-line configuration on top of it.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import configparser
|
import configparser
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
from flake8.options import config
|
from flake8.options import config
|
||||||
|
|
@ -19,7 +20,7 @@ def aggregate_options(
|
||||||
manager: OptionManager,
|
manager: OptionManager,
|
||||||
cfg: configparser.RawConfigParser,
|
cfg: configparser.RawConfigParser,
|
||||||
cfg_dir: str,
|
cfg_dir: str,
|
||||||
argv: Optional[Sequence[str]],
|
argv: Sequence[str] | None,
|
||||||
) -> argparse.Namespace:
|
) -> argparse.Namespace:
|
||||||
"""Aggregate and merge CLI and config file options."""
|
"""Aggregate and merge CLI and config file options."""
|
||||||
# Get defaults from the option parser
|
# Get defaults from the option parser
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
"""Config handling logic for Flake8."""
|
"""Config handling logic for Flake8."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import configparser
|
import configparser
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
|
||||||
from typing import List
|
|
||||||
from typing import Optional
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from flake8 import exceptions
|
from flake8 import exceptions
|
||||||
from flake8.options.manager import OptionManager
|
from flake8.options.manager import OptionManager
|
||||||
|
|
@ -14,13 +12,13 @@ from flake8.options.manager import OptionManager
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _stat_key(s: str) -> Tuple[int, int]:
|
def _stat_key(s: str) -> tuple[int, int]:
|
||||||
# same as what's used by samefile / samestat
|
# same as what's used by samefile / samestat
|
||||||
st = os.stat(s)
|
st = os.stat(s)
|
||||||
return st.st_ino, st.st_dev
|
return st.st_ino, st.st_dev
|
||||||
|
|
||||||
|
|
||||||
def _find_config_file(path: str) -> Optional[str]:
|
def _find_config_file(path: str) -> str | None:
|
||||||
# on windows if the homedir isn't detected this returns back `~`
|
# on windows if the homedir isn't detected this returns back `~`
|
||||||
home = os.path.expanduser("~")
|
home = os.path.expanduser("~")
|
||||||
try:
|
try:
|
||||||
|
|
@ -55,11 +53,11 @@ def _find_config_file(path: str) -> Optional[str]:
|
||||||
|
|
||||||
|
|
||||||
def load_config(
|
def load_config(
|
||||||
config: Optional[str],
|
config: str | None,
|
||||||
extra: List[str],
|
extra: list[str],
|
||||||
*,
|
*,
|
||||||
isolated: bool = False,
|
isolated: bool = False,
|
||||||
) -> Tuple[configparser.RawConfigParser, str]:
|
) -> tuple[configparser.RawConfigParser, str]:
|
||||||
"""Load the configuration given the user options.
|
"""Load the configuration given the user options.
|
||||||
|
|
||||||
- in ``isolated`` mode, return an empty configuration
|
- in ``isolated`` mode, return an empty configuration
|
||||||
|
|
@ -97,7 +95,7 @@ def parse_config(
|
||||||
option_manager: OptionManager,
|
option_manager: OptionManager,
|
||||||
cfg: configparser.RawConfigParser,
|
cfg: configparser.RawConfigParser,
|
||||||
cfg_dir: str,
|
cfg_dir: str,
|
||||||
) -> Dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Parse and normalize the typed configuration options."""
|
"""Parse and normalize the typed configuration options."""
|
||||||
if "flake8" not in cfg:
|
if "flake8" not in cfg:
|
||||||
return {}
|
return {}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,14 @@
|
||||||
"""Option handling and Option management logic."""
|
"""Option handling and Option management logic."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import enum
|
import enum
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Dict
|
|
||||||
from typing import List
|
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
from typing import Type
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
from flake8.plugins.finder import Plugins
|
from flake8.plugins.finder import Plugins
|
||||||
|
|
@ -24,7 +20,7 @@ LOG = logging.getLogger(__name__)
|
||||||
_ARG = enum.Enum("_ARG", "NO")
|
_ARG = enum.Enum("_ARG", "NO")
|
||||||
|
|
||||||
|
|
||||||
_optparse_callable_map: Dict[str, Union[Type[Any], _ARG]] = {
|
_optparse_callable_map: dict[str, type[Any] | _ARG] = {
|
||||||
"int": int,
|
"int": int,
|
||||||
"long": int,
|
"long": int,
|
||||||
"string": str,
|
"string": str,
|
||||||
|
|
@ -44,7 +40,7 @@ class _CallbackAction(argparse.Action):
|
||||||
*args: Any,
|
*args: Any,
|
||||||
callback: Callable[..., Any],
|
callback: Callable[..., Any],
|
||||||
callback_args: Sequence[Any] = (),
|
callback_args: Sequence[Any] = (),
|
||||||
callback_kwargs: Optional[Dict[str, Any]] = None,
|
callback_kwargs: dict[str, Any] | None = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
self._callback = callback
|
self._callback = callback
|
||||||
|
|
@ -56,8 +52,8 @@ class _CallbackAction(argparse.Action):
|
||||||
self,
|
self,
|
||||||
parser: argparse.ArgumentParser,
|
parser: argparse.ArgumentParser,
|
||||||
namespace: argparse.Namespace,
|
namespace: argparse.Namespace,
|
||||||
values: Optional[Union[Sequence[str], str]],
|
values: Sequence[str] | str | None,
|
||||||
option_string: Optional[str] = None,
|
option_string: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
if not values:
|
if not values:
|
||||||
values = None
|
values = None
|
||||||
|
|
@ -78,8 +74,8 @@ def _flake8_normalize(
|
||||||
*args: str,
|
*args: str,
|
||||||
comma_separated_list: bool = False,
|
comma_separated_list: bool = False,
|
||||||
normalize_paths: bool = False,
|
normalize_paths: bool = False,
|
||||||
) -> Union[str, List[str]]:
|
) -> str | list[str]:
|
||||||
ret: Union[str, List[str]] = value
|
ret: str | list[str] = value
|
||||||
if comma_separated_list and isinstance(ret, str):
|
if comma_separated_list and isinstance(ret, str):
|
||||||
ret = utils.parse_comma_separated_list(value)
|
ret = utils.parse_comma_separated_list(value)
|
||||||
|
|
||||||
|
|
@ -97,24 +93,24 @@ class Option:
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
short_option_name: Union[str, _ARG] = _ARG.NO,
|
short_option_name: str | _ARG = _ARG.NO,
|
||||||
long_option_name: Union[str, _ARG] = _ARG.NO,
|
long_option_name: 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: Union[str, Type[argparse.Action], _ARG] = _ARG.NO,
|
action: str | type[argparse.Action] | _ARG = _ARG.NO,
|
||||||
default: Union[Any, _ARG] = _ARG.NO,
|
default: Any | _ARG = _ARG.NO,
|
||||||
type: Union[str, Callable[..., Any], _ARG] = _ARG.NO,
|
type: str | Callable[..., Any] | _ARG = _ARG.NO,
|
||||||
dest: Union[str, _ARG] = _ARG.NO,
|
dest: str | _ARG = _ARG.NO,
|
||||||
nargs: Union[int, str, _ARG] = _ARG.NO,
|
nargs: int | str | _ARG = _ARG.NO,
|
||||||
const: Union[Any, _ARG] = _ARG.NO,
|
const: Any | _ARG = _ARG.NO,
|
||||||
choices: Union[Sequence[Any], _ARG] = _ARG.NO,
|
choices: Sequence[Any] | _ARG = _ARG.NO,
|
||||||
help: Union[str, _ARG] = _ARG.NO,
|
help: str | _ARG = _ARG.NO,
|
||||||
metavar: Union[str, _ARG] = _ARG.NO,
|
metavar: str | _ARG = _ARG.NO,
|
||||||
# deprecated optparse-only options
|
# deprecated optparse-only options
|
||||||
callback: Union[Callable[..., Any], _ARG] = _ARG.NO,
|
callback: Callable[..., Any] | _ARG = _ARG.NO,
|
||||||
callback_args: Union[Sequence[Any], _ARG] = _ARG.NO,
|
callback_args: Sequence[Any] | _ARG = _ARG.NO,
|
||||||
callback_kwargs: Union[Mapping[str, Any], _ARG] = _ARG.NO,
|
callback_kwargs: 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: Union[bool, _ARG] = _ARG.NO,
|
required: bool | _ARG = _ARG.NO,
|
||||||
# Options below here are specific to Flake8
|
# Options below here are specific to Flake8
|
||||||
parse_from_config: bool = False,
|
parse_from_config: bool = False,
|
||||||
comma_separated_list: bool = False,
|
comma_separated_list: bool = False,
|
||||||
|
|
@ -247,7 +243,7 @@ class Option:
|
||||||
self.help = help
|
self.help = help
|
||||||
self.metavar = metavar
|
self.metavar = metavar
|
||||||
self.required = required
|
self.required = required
|
||||||
self.option_kwargs: Dict[str, Union[Any, _ARG]] = {
|
self.option_kwargs: dict[str, Any | _ARG] = {
|
||||||
"action": self.action,
|
"action": self.action,
|
||||||
"default": self.default,
|
"default": self.default,
|
||||||
"type": self.type,
|
"type": self.type,
|
||||||
|
|
@ -268,7 +264,7 @@ class Option:
|
||||||
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: Optional[str] = None
|
self.config_name: str | None = 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(
|
||||||
|
|
@ -280,7 +276,7 @@ class Option:
|
||||||
self._opt = None
|
self._opt = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filtered_option_kwargs(self) -> 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
|
||||||
|
|
@ -307,7 +303,7 @@ class Option:
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def to_argparse(self) -> Tuple[List[str], Dict[str, Any]]:
|
def to_argparse(self) -> 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
|
||||||
|
|
||||||
|
|
@ -320,7 +316,7 @@ class OptionManager:
|
||||||
*,
|
*,
|
||||||
version: str,
|
version: str,
|
||||||
plugin_versions: str,
|
plugin_versions: str,
|
||||||
parents: List[argparse.ArgumentParser],
|
parents: list[argparse.ArgumentParser],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize an instance of an OptionManager.
|
"""Initialize an instance of an OptionManager.
|
||||||
|
|
||||||
|
|
@ -350,17 +346,17 @@ class OptionManager:
|
||||||
)
|
)
|
||||||
self.parser.add_argument("filenames", nargs="*", metavar="filename")
|
self.parser.add_argument("filenames", nargs="*", metavar="filename")
|
||||||
|
|
||||||
self.config_options_dict: Dict[str, Option] = {}
|
self.config_options_dict: dict[str, Option] = {}
|
||||||
self.options: List[Option] = []
|
self.options: list[Option] = []
|
||||||
self.extended_default_ignore: List[str] = []
|
self.extended_default_ignore: list[str] = []
|
||||||
self.extended_default_select: List[str] = []
|
self.extended_default_select: list[str] = []
|
||||||
|
|
||||||
self._current_group: Optional[argparse._ArgumentGroup] = None
|
self._current_group: argparse._ArgumentGroup | None = None
|
||||||
|
|
||||||
# TODO: maybe make this a free function to reduce api surface area
|
# TODO: maybe make this a free function to reduce api surface area
|
||||||
def register_plugins(self, plugins: Plugins) -> None:
|
def register_plugins(self, plugins: Plugins) -> None:
|
||||||
"""Register the plugin options (if needed)."""
|
"""Register the plugin options (if needed)."""
|
||||||
groups: Dict[str, argparse._ArgumentGroup] = {}
|
groups: dict[str, argparse._ArgumentGroup] = {}
|
||||||
|
|
||||||
def _set_group(name: str) -> None:
|
def _set_group(name: str) -> None:
|
||||||
try:
|
try:
|
||||||
|
|
@ -428,8 +424,8 @@ class OptionManager:
|
||||||
|
|
||||||
def parse_args(
|
def parse_args(
|
||||||
self,
|
self,
|
||||||
args: Optional[Sequence[str]] = None,
|
args: Sequence[str] | None = None,
|
||||||
values: Optional[argparse.Namespace] = None,
|
values: argparse.Namespace | None = None,
|
||||||
) -> argparse.Namespace:
|
) -> argparse.Namespace:
|
||||||
"""Proxy to calling the OptionParser's parse_args method."""
|
"""Proxy to calling the OptionParser's parse_args method."""
|
||||||
if values:
|
if values:
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
"""Submodule of built-in plugins and plugin managers."""
|
"""Submodule of built-in plugins and plugin managers."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Functions related to finding and loading plugins."""
|
"""Functions related to finding and loading plugins."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import configparser
|
import configparser
|
||||||
import inspect
|
import inspect
|
||||||
import itertools
|
import itertools
|
||||||
|
|
@ -6,14 +8,9 @@ import logging
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
|
||||||
from typing import FrozenSet
|
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from typing import List
|
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Optional
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
from flake8._compat import importlib_metadata
|
from flake8._compat import importlib_metadata
|
||||||
|
|
@ -45,7 +42,7 @@ class LoadedPlugin(NamedTuple):
|
||||||
|
|
||||||
plugin: Plugin
|
plugin: Plugin
|
||||||
obj: Any
|
obj: Any
|
||||||
parameters: Dict[str, bool]
|
parameters: dict[str, bool]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def entry_name(self) -> str:
|
def entry_name(self) -> str:
|
||||||
|
|
@ -61,17 +58,17 @@ class LoadedPlugin(NamedTuple):
|
||||||
class Checkers(NamedTuple):
|
class Checkers(NamedTuple):
|
||||||
"""Classified plugins needed for checking."""
|
"""Classified plugins needed for checking."""
|
||||||
|
|
||||||
tree: List[LoadedPlugin]
|
tree: list[LoadedPlugin]
|
||||||
logical_line: List[LoadedPlugin]
|
logical_line: list[LoadedPlugin]
|
||||||
physical_line: List[LoadedPlugin]
|
physical_line: list[LoadedPlugin]
|
||||||
|
|
||||||
|
|
||||||
class Plugins(NamedTuple):
|
class Plugins(NamedTuple):
|
||||||
"""Classified plugins."""
|
"""Classified plugins."""
|
||||||
|
|
||||||
checkers: Checkers
|
checkers: Checkers
|
||||||
reporters: Dict[str, LoadedPlugin]
|
reporters: dict[str, LoadedPlugin]
|
||||||
disabled: List[LoadedPlugin]
|
disabled: list[LoadedPlugin]
|
||||||
|
|
||||||
def all_plugins(self) -> Generator[LoadedPlugin, None, None]:
|
def all_plugins(self) -> Generator[LoadedPlugin, None, None]:
|
||||||
"""Return an iterator over all :class:`LoadedPlugin`s."""
|
"""Return an iterator over all :class:`LoadedPlugin`s."""
|
||||||
|
|
@ -96,12 +93,12 @@ class Plugins(NamedTuple):
|
||||||
class PluginOptions(NamedTuple):
|
class PluginOptions(NamedTuple):
|
||||||
"""Options related to plugin loading."""
|
"""Options related to plugin loading."""
|
||||||
|
|
||||||
local_plugin_paths: Tuple[str, ...]
|
local_plugin_paths: tuple[str, ...]
|
||||||
enable_extensions: FrozenSet[str]
|
enable_extensions: frozenset[str]
|
||||||
require_plugins: FrozenSet[str]
|
require_plugins: frozenset[str]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def blank(cls) -> "PluginOptions":
|
def blank(cls) -> PluginOptions:
|
||||||
"""Make a blank PluginOptions, mostly used for tests."""
|
"""Make a blank PluginOptions, mostly used for tests."""
|
||||||
return cls(
|
return cls(
|
||||||
local_plugin_paths=(),
|
local_plugin_paths=(),
|
||||||
|
|
@ -113,8 +110,8 @@ class PluginOptions(NamedTuple):
|
||||||
def _parse_option(
|
def _parse_option(
|
||||||
cfg: configparser.RawConfigParser,
|
cfg: configparser.RawConfigParser,
|
||||||
cfg_opt_name: str,
|
cfg_opt_name: str,
|
||||||
opt: Optional[str],
|
opt: str | None,
|
||||||
) -> List[str]:
|
) -> list[str]:
|
||||||
# specified on commandline: use that
|
# specified on commandline: use that
|
||||||
if opt is not None:
|
if opt is not None:
|
||||||
return utils.parse_comma_separated_list(opt)
|
return utils.parse_comma_separated_list(opt)
|
||||||
|
|
@ -133,8 +130,8 @@ def parse_plugin_options(
|
||||||
cfg: configparser.RawConfigParser,
|
cfg: configparser.RawConfigParser,
|
||||||
cfg_dir: str,
|
cfg_dir: str,
|
||||||
*,
|
*,
|
||||||
enable_extensions: Optional[str],
|
enable_extensions: str | None,
|
||||||
require_plugins: Optional[str],
|
require_plugins: str | None,
|
||||||
) -> PluginOptions:
|
) -> PluginOptions:
|
||||||
"""Parse plugin loading related options."""
|
"""Parse plugin loading related options."""
|
||||||
paths_s = cfg.get("flake8:local-plugins", "paths", fallback="").strip()
|
paths_s = cfg.get("flake8:local-plugins", "paths", fallback="").strip()
|
||||||
|
|
@ -231,8 +228,8 @@ def _find_local_plugins(
|
||||||
|
|
||||||
|
|
||||||
def _check_required_plugins(
|
def _check_required_plugins(
|
||||||
plugins: List[Plugin],
|
plugins: list[Plugin],
|
||||||
expected: FrozenSet[str],
|
expected: frozenset[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
plugin_names = {
|
plugin_names = {
|
||||||
utils.normalize_pypi_name(plugin.package) for plugin in plugins
|
utils.normalize_pypi_name(plugin.package) for plugin in plugins
|
||||||
|
|
@ -252,7 +249,7 @@ def _check_required_plugins(
|
||||||
def find_plugins(
|
def find_plugins(
|
||||||
cfg: configparser.RawConfigParser,
|
cfg: configparser.RawConfigParser,
|
||||||
opts: PluginOptions,
|
opts: PluginOptions,
|
||||||
) -> List[Plugin]:
|
) -> list[Plugin]:
|
||||||
"""Discovers all plugins (but does not load them)."""
|
"""Discovers all plugins (but does not load them)."""
|
||||||
ret = [*_find_importlib_plugins(), *_find_local_plugins(cfg)]
|
ret = [*_find_importlib_plugins(), *_find_local_plugins(cfg)]
|
||||||
|
|
||||||
|
|
@ -264,7 +261,7 @@ def find_plugins(
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def _parameters_for(func: Any) -> Dict[str, bool]:
|
def _parameters_for(func: Any) -> 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
|
||||||
|
|
@ -305,15 +302,15 @@ def _load_plugin(plugin: Plugin) -> LoadedPlugin:
|
||||||
|
|
||||||
|
|
||||||
def _import_plugins(
|
def _import_plugins(
|
||||||
plugins: List[Plugin],
|
plugins: list[Plugin],
|
||||||
opts: PluginOptions,
|
opts: PluginOptions,
|
||||||
) -> List[LoadedPlugin]:
|
) -> list[LoadedPlugin]:
|
||||||
sys.path.extend(opts.local_plugin_paths)
|
sys.path.extend(opts.local_plugin_paths)
|
||||||
return [_load_plugin(p) for p in plugins]
|
return [_load_plugin(p) for p in plugins]
|
||||||
|
|
||||||
|
|
||||||
def _classify_plugins(
|
def _classify_plugins(
|
||||||
plugins: List[LoadedPlugin],
|
plugins: list[LoadedPlugin],
|
||||||
opts: PluginOptions,
|
opts: PluginOptions,
|
||||||
) -> Plugins:
|
) -> Plugins:
|
||||||
tree = []
|
tree = []
|
||||||
|
|
@ -358,7 +355,7 @@ def _classify_plugins(
|
||||||
|
|
||||||
|
|
||||||
def load_plugins(
|
def load_plugins(
|
||||||
plugins: List[Plugin],
|
plugins: list[Plugin],
|
||||||
opts: PluginOptions,
|
opts: PluginOptions,
|
||||||
) -> Plugins:
|
) -> Plugins:
|
||||||
"""Load and classify all flake8 plugins.
|
"""Load and classify all flake8 plugins.
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
"""Generated using ./bin/gen-pycodestyle-plugin."""
|
"""Generated using ./bin/gen-pycodestyle-plugin."""
|
||||||
# fmt: off
|
# fmt: off
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pycodestyle import ambiguous_identifier as _ambiguous_identifier
|
from pycodestyle import ambiguous_identifier as _ambiguous_identifier
|
||||||
from pycodestyle import bare_except as _bare_except
|
from pycodestyle import bare_except as _bare_except
|
||||||
|
|
@ -60,7 +61,7 @@ def pycodestyle_logical(
|
||||||
previous_unindented_logical_line: Any,
|
previous_unindented_logical_line: Any,
|
||||||
tokens: Any,
|
tokens: Any,
|
||||||
verbose: Any,
|
verbose: Any,
|
||||||
) -> Generator[Tuple[int, str], None, None]:
|
) -> Generator[tuple[int, str], None, None]:
|
||||||
"""Run pycodestyle logical checks."""
|
"""Run pycodestyle logical checks."""
|
||||||
yield from _ambiguous_identifier(logical_line, tokens)
|
yield from _ambiguous_identifier(logical_line, tokens)
|
||||||
yield from _bare_except(logical_line, noqa)
|
yield from _bare_except(logical_line, noqa)
|
||||||
|
|
@ -104,7 +105,7 @@ def pycodestyle_physical(
|
||||||
noqa: Any,
|
noqa: Any,
|
||||||
physical_line: Any,
|
physical_line: Any,
|
||||||
total_lines: Any,
|
total_lines: Any,
|
||||||
) -> Generator[Tuple[int, str], None, None]:
|
) -> Generator[tuple[int, str], None, None]:
|
||||||
"""Run pycodestyle physical checks."""
|
"""Run pycodestyle physical checks."""
|
||||||
ret = _maximum_line_length(physical_line, max_line_length, multiline, line_number, noqa) # noqa: E501
|
ret = _maximum_line_length(physical_line, max_line_length, multiline, line_number, noqa) # noqa: E501
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
"""Plugin built-in to Flake8 to treat pyflakes as a plugin."""
|
"""Plugin built-in to Flake8 to treat pyflakes as a plugin."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import ast
|
import ast
|
||||||
import os
|
import os
|
||||||
import tokenize
|
import tokenize
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import List
|
|
||||||
from typing import Tuple
|
|
||||||
from typing import Type
|
|
||||||
|
|
||||||
import pyflakes.checker
|
import pyflakes.checker
|
||||||
|
|
||||||
|
|
@ -68,13 +67,13 @@ class FlakesChecker(pyflakes.checker.Checker):
|
||||||
"""Subclass the Pyflakes checker to conform with the flake8 API."""
|
"""Subclass the Pyflakes checker to conform with the flake8 API."""
|
||||||
|
|
||||||
with_doctest = False
|
with_doctest = False
|
||||||
include_in_doctest: List[str] = []
|
include_in_doctest: list[str] = []
|
||||||
exclude_from_doctest: List[str] = []
|
exclude_from_doctest: list[str] = []
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
tree: ast.AST,
|
tree: ast.AST,
|
||||||
file_tokens: List[tokenize.TokenInfo],
|
file_tokens: list[tokenize.TokenInfo],
|
||||||
filename: str,
|
filename: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the PyFlakes plugin with an AST tree and filename."""
|
"""Initialize the PyFlakes plugin with an AST tree and filename."""
|
||||||
|
|
@ -180,7 +179,7 @@ class FlakesChecker(pyflakes.checker.Checker):
|
||||||
f"both for doctesting."
|
f"both for doctesting."
|
||||||
)
|
)
|
||||||
|
|
||||||
def run(self) -> Generator[Tuple[int, int, str, Type[Any]], None, None]:
|
def run(self) -> Generator[tuple[int, int, str, type[Any]], None, None]:
|
||||||
"""Run the plugin."""
|
"""Run the plugin."""
|
||||||
for message in self.messages:
|
for message in self.messages:
|
||||||
col = getattr(message, "col", 0)
|
col = getattr(message, "col", 0)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
"""Functions for construcing the requested report plugin."""
|
"""Functions for construcing the requested report plugin."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
from flake8.formatting.base import BaseFormatter
|
from flake8.formatting.base import BaseFormatter
|
||||||
from flake8.plugins.finder import LoadedPlugin
|
from flake8.plugins.finder import LoadedPlugin
|
||||||
|
|
@ -10,7 +11,7 @@ LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def make(
|
def make(
|
||||||
reporters: Dict[str, LoadedPlugin],
|
reporters: dict[str, LoadedPlugin],
|
||||||
options: argparse.Namespace,
|
options: argparse.Namespace,
|
||||||
) -> BaseFormatter:
|
) -> BaseFormatter:
|
||||||
"""Make the formatter from the requested user options.
|
"""Make the formatter from the requested user options.
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
"""Module containing our file processor that tokenizes a file for checks."""
|
"""Module containing our file processor that tokenizes a file for checks."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import ast
|
import ast
|
||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import tokenize
|
import tokenize
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
from flake8 import defaults
|
from flake8 import defaults
|
||||||
|
|
@ -61,7 +61,7 @@ class FileProcessor:
|
||||||
self,
|
self,
|
||||||
filename: str,
|
filename: str,
|
||||||
options: argparse.Namespace,
|
options: argparse.Namespace,
|
||||||
lines: Optional[List[str]] = None,
|
lines: list[str] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialice our file processor.
|
"""Initialice our file processor.
|
||||||
|
|
||||||
|
|
@ -78,13 +78,13 @@ class FileProcessor:
|
||||||
#: 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: Dict[str, Dict[Any, Any]] = {}
|
self._checker_states: dict[str, dict[Any, Any]] = {}
|
||||||
#: Current checker state
|
#: Current checker state
|
||||||
self.checker_state: 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: Optional[str] = None
|
self.indent_char: str | None = 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
|
||||||
|
|
@ -106,19 +106,19 @@ class FileProcessor:
|
||||||
#: 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: List[tokenize.TokenInfo] = []
|
self.tokens: list[tokenize.TokenInfo] = []
|
||||||
#: 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: Optional[List[tokenize.TokenInfo]] = None
|
self._file_tokens: list[tokenize.TokenInfo] | None = 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: Optional[Dict[int, str]] = None
|
self._noqa_line_mapping: dict[int, str] | None = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def file_tokens(self) -> List[tokenize.TokenInfo]:
|
def file_tokens(self) -> list[tokenize.TokenInfo]:
|
||||||
"""Return the complete set of tokens for a file."""
|
"""Return the complete set of tokens for a file."""
|
||||||
if self._file_tokens is None:
|
if self._file_tokens is None:
|
||||||
line_iter = iter(self.lines)
|
line_iter = iter(self.lines)
|
||||||
|
|
@ -217,7 +217,7 @@ class FileProcessor:
|
||||||
"""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) -> Tuple[str, str, _LogicalMapping]:
|
def build_logical_line(self) -> 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)
|
||||||
|
|
@ -240,9 +240,9 @@ class FileProcessor:
|
||||||
|
|
||||||
def keyword_arguments_for(
|
def keyword_arguments_for(
|
||||||
self,
|
self,
|
||||||
parameters: Dict[str, bool],
|
parameters: dict[str, bool],
|
||||||
arguments: Dict[str, Any],
|
arguments: dict[str, Any],
|
||||||
) -> Dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Generate the keyword arguments for a list of parameters."""
|
"""Generate the keyword arguments for a list of parameters."""
|
||||||
ret = {}
|
ret = {}
|
||||||
for param, required in parameters.items():
|
for param, required in parameters.items():
|
||||||
|
|
@ -269,12 +269,12 @@ class FileProcessor:
|
||||||
self.tokens.append(token)
|
self.tokens.append(token)
|
||||||
yield token
|
yield token
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
def noqa_line_for(self, line_number: int) -> Optional[str]:
|
def noqa_line_for(self, line_number: int) -> str | None:
|
||||||
"""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:
|
||||||
|
|
@ -324,7 +324,7 @@ class FileProcessor:
|
||||||
self.indent_char = line[0]
|
self.indent_char = line[0]
|
||||||
return line
|
return line
|
||||||
|
|
||||||
def read_lines(self) -> List[str]:
|
def read_lines(self) -> 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"
|
||||||
|
|
@ -333,7 +333,7 @@ class FileProcessor:
|
||||||
lines = self.read_lines_from_filename()
|
lines = self.read_lines_from_filename()
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def read_lines_from_filename(self) -> List[str]:
|
def read_lines_from_filename(self) -> list[str]:
|
||||||
"""Read the lines for a file."""
|
"""Read the lines for a file."""
|
||||||
try:
|
try:
|
||||||
with tokenize.open(self.filename) as fd:
|
with tokenize.open(self.filename) as fd:
|
||||||
|
|
@ -344,7 +344,7 @@ class FileProcessor:
|
||||||
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_stdin(self) -> List[str]:
|
def read_lines_from_stdin(self) -> list[str]:
|
||||||
"""Read the lines from standard in."""
|
"""Read the lines from standard in."""
|
||||||
return utils.stdin_get_lines()
|
return utils.stdin_get_lines()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
"""Statistic collection logic for Flake8."""
|
"""Statistic collection logic for Flake8."""
|
||||||
from typing import Dict
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import List
|
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from flake8.violation import Violation
|
from flake8.violation import Violation
|
||||||
|
|
||||||
|
|
@ -13,9 +12,9 @@ class Statistics:
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
"""Initialize the underlying dictionary for our statistics."""
|
"""Initialize the underlying dictionary for our statistics."""
|
||||||
self._store: Dict[Key, "Statistic"] = {}
|
self._store: dict[Key, Statistic] = {}
|
||||||
|
|
||||||
def error_codes(self) -> List[str]:
|
def error_codes(self) -> list[str]:
|
||||||
"""Return all unique error codes stored.
|
"""Return all unique error codes stored.
|
||||||
|
|
||||||
:returns:
|
:returns:
|
||||||
|
|
@ -23,7 +22,7 @@ class Statistics:
|
||||||
"""
|
"""
|
||||||
return sorted({key.code for key in self._store})
|
return sorted({key.code for key in self._store})
|
||||||
|
|
||||||
def record(self, error: "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:
|
||||||
|
|
@ -36,8 +35,8 @@ class Statistics:
|
||||||
self._store[key].increment()
|
self._store[key].increment()
|
||||||
|
|
||||||
def statistics_for(
|
def statistics_for(
|
||||||
self, prefix: str, filename: Optional[str] = None
|
self, prefix: str, filename: str | None = None
|
||||||
) -> Generator["Statistic", None, 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 +78,11 @@ class Key(NamedTuple):
|
||||||
code: str
|
code: str
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_from(cls, error: "Violation") -> "Key":
|
def create_from(cls, error: Violation) -> Key:
|
||||||
"""Create a Key from :class:`flake8.violation.Violation`."""
|
"""Create a Key from :class:`flake8.violation.Violation`."""
|
||||||
return cls(filename=error.filename, code=error.code)
|
return cls(filename=error.filename, code=error.code)
|
||||||
|
|
||||||
def matches(self, prefix: str, filename: Optional[str]) -> bool:
|
def matches(self, prefix: str, filename: str | None) -> bool:
|
||||||
"""Determine if this key matches some constraints.
|
"""Determine if this key matches some constraints.
|
||||||
|
|
||||||
:param prefix:
|
:param prefix:
|
||||||
|
|
@ -118,7 +117,7 @@ class Statistic:
|
||||||
self.count = count
|
self.count = count
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_from(cls, error: "Violation") -> "Statistic":
|
def create_from(cls, error: Violation) -> Statistic:
|
||||||
"""Create a Statistic from a :class:`flake8.violation.Violation`."""
|
"""Create a Statistic from a :class:`flake8.violation.Violation`."""
|
||||||
return cls(
|
return cls(
|
||||||
error_code=error.code,
|
error_code=error.code,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Implementation of the StyleGuide used by Flake8."""
|
"""Implementation of the StyleGuide used by Flake8."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import contextlib
|
import contextlib
|
||||||
import copy
|
import copy
|
||||||
|
|
@ -6,14 +8,8 @@ import enum
|
||||||
import functools
|
import functools
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict
|
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import List
|
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
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
|
||||||
|
|
@ -49,20 +45,20 @@ class Decision(enum.Enum):
|
||||||
|
|
||||||
def _explicitly_chosen(
|
def _explicitly_chosen(
|
||||||
*,
|
*,
|
||||||
option: Optional[List[str]],
|
option: list[str] | None,
|
||||||
extend: Optional[List[str]],
|
extend: list[str] | None,
|
||||||
) -> Tuple[str, ...]:
|
) -> tuple[str, ...]:
|
||||||
ret = [*(option or []), *(extend or [])]
|
ret = [*(option or []), *(extend or [])]
|
||||||
return tuple(sorted(ret, reverse=True))
|
return tuple(sorted(ret, reverse=True))
|
||||||
|
|
||||||
|
|
||||||
def _select_ignore(
|
def _select_ignore(
|
||||||
*,
|
*,
|
||||||
option: Optional[List[str]],
|
option: list[str] | None,
|
||||||
default: Tuple[str, ...],
|
default: tuple[str, ...],
|
||||||
extended_default: List[str],
|
extended_default: list[str],
|
||||||
extend: Optional[List[str]],
|
extend: list[str] | None,
|
||||||
) -> Tuple[str, ...]:
|
) -> tuple[str, ...]:
|
||||||
# option was explicitly set, ignore the default and extended default
|
# option was explicitly set, ignore the default and extended default
|
||||||
if option is not None:
|
if option is not None:
|
||||||
ret = [*option, *(extend or [])]
|
ret = [*option, *(extend or [])]
|
||||||
|
|
@ -80,7 +76,7 @@ class DecisionEngine:
|
||||||
|
|
||||||
def __init__(self, options: argparse.Namespace) -> None:
|
def __init__(self, options: argparse.Namespace) -> None:
|
||||||
"""Initialize the engine."""
|
"""Initialize the engine."""
|
||||||
self.cache: Dict[str, Decision] = {}
|
self.cache: dict[str, Decision] = {}
|
||||||
|
|
||||||
self.selected_explicitly = _explicitly_chosen(
|
self.selected_explicitly = _explicitly_chosen(
|
||||||
option=options.select,
|
option=options.select,
|
||||||
|
|
@ -104,7 +100,7 @@ class DecisionEngine:
|
||||||
extend=options.extend_ignore,
|
extend=options.extend_ignore,
|
||||||
)
|
)
|
||||||
|
|
||||||
def was_selected(self, code: str) -> Union[Selected, Ignored]:
|
def was_selected(self, code: str) -> Selected | Ignored:
|
||||||
"""Determine if the code has been selected by the user.
|
"""Determine if the code has been selected by the user.
|
||||||
|
|
||||||
:param code: The code for the check that has been run.
|
:param code: The code for the check that has been run.
|
||||||
|
|
@ -122,7 +118,7 @@ class DecisionEngine:
|
||||||
else:
|
else:
|
||||||
return Ignored.Implicitly
|
return Ignored.Implicitly
|
||||||
|
|
||||||
def was_ignored(self, code: str) -> Union[Selected, Ignored]:
|
def was_ignored(self, code: str) -> Selected | Ignored:
|
||||||
"""Determine if the code has been ignored by the user.
|
"""Determine if the code has been ignored by the user.
|
||||||
|
|
||||||
:param code:
|
:param code:
|
||||||
|
|
@ -211,7 +207,7 @@ class StyleGuideManager:
|
||||||
self,
|
self,
|
||||||
options: argparse.Namespace,
|
options: argparse.Namespace,
|
||||||
formatter: base_formatter.BaseFormatter,
|
formatter: base_formatter.BaseFormatter,
|
||||||
decider: Optional[DecisionEngine] = None,
|
decider: DecisionEngine | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize our StyleGuide.
|
"""Initialize our StyleGuide.
|
||||||
|
|
||||||
|
|
@ -221,7 +217,7 @@ class StyleGuideManager:
|
||||||
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: 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
|
||||||
)
|
)
|
||||||
|
|
@ -238,7 +234,7 @@ class StyleGuideManager:
|
||||||
|
|
||||||
def populate_style_guides_with(
|
def populate_style_guides_with(
|
||||||
self, options: argparse.Namespace
|
self, options: argparse.Namespace
|
||||||
) -> Generator["StyleGuide", None, None]:
|
) -> 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:
|
||||||
|
|
@ -252,7 +248,7 @@ class StyleGuideManager:
|
||||||
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:
|
||||||
"""Find the StyleGuide for the filename in particular."""
|
"""Find the StyleGuide for the filename in particular."""
|
||||||
return max(
|
return max(
|
||||||
(g for g in self.style_guides if g.applies_to(filename)),
|
(g for g in self.style_guides if g.applies_to(filename)),
|
||||||
|
|
@ -262,7 +258,7 @@ class StyleGuideManager:
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def processing_file(
|
def processing_file(
|
||||||
self, filename: str
|
self, filename: str
|
||||||
) -> Generator["StyleGuide", None, None]:
|
) -> 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):
|
||||||
|
|
@ -275,7 +271,7 @@ class StyleGuideManager:
|
||||||
line_number: int,
|
line_number: int,
|
||||||
column_number: int,
|
column_number: int,
|
||||||
text: str,
|
text: str,
|
||||||
physical_line: Optional[str] = None,
|
physical_line: str | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Handle an error reported by a check.
|
"""Handle an error reported by a check.
|
||||||
|
|
||||||
|
|
@ -302,7 +298,7 @@ class StyleGuideManager:
|
||||||
code, filename, line_number, column_number, text, physical_line
|
code, filename, line_number, column_number, text, physical_line
|
||||||
)
|
)
|
||||||
|
|
||||||
def add_diff_ranges(self, diffinfo: Dict[str, Set[int]]) -> None:
|
def add_diff_ranges(self, diffinfo: 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
|
||||||
|
|
@ -323,8 +319,8 @@ class StyleGuide:
|
||||||
options: argparse.Namespace,
|
options: argparse.Namespace,
|
||||||
formatter: base_formatter.BaseFormatter,
|
formatter: base_formatter.BaseFormatter,
|
||||||
stats: statistics.Statistics,
|
stats: statistics.Statistics,
|
||||||
filename: Optional[str] = None,
|
filename: str | None = None,
|
||||||
decider: Optional[DecisionEngine] = None,
|
decider: DecisionEngine | None = None,
|
||||||
):
|
):
|
||||||
"""Initialize our StyleGuide.
|
"""Initialize our StyleGuide.
|
||||||
|
|
||||||
|
|
@ -337,7 +333,7 @@ class StyleGuide:
|
||||||
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: Dict[str, Set[int]] = {}
|
self._parsed_diff: dict[str, set[int]] = {}
|
||||||
|
|
||||||
def __repr__(self) -> 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."""
|
||||||
|
|
@ -345,9 +341,9 @@ class StyleGuide:
|
||||||
|
|
||||||
def copy(
|
def copy(
|
||||||
self,
|
self,
|
||||||
filename: Optional[str] = None,
|
filename: str | None = None,
|
||||||
extend_ignore_with: Optional[Sequence[str]] = None,
|
extend_ignore_with: Sequence[str] | None = None,
|
||||||
) -> "StyleGuide":
|
) -> 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)
|
||||||
|
|
@ -360,7 +356,7 @@ class StyleGuide:
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def processing_file(
|
def processing_file(
|
||||||
self, filename: str
|
self, filename: str
|
||||||
) -> Generator["StyleGuide", None, None]:
|
) -> 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
|
||||||
|
|
@ -405,7 +401,7 @@ class StyleGuide:
|
||||||
line_number: int,
|
line_number: int,
|
||||||
column_number: int,
|
column_number: int,
|
||||||
text: str,
|
text: str,
|
||||||
physical_line: Optional[str] = None,
|
physical_line: str | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Handle an error reported by a check.
|
"""Handle an error reported by a check.
|
||||||
|
|
||||||
|
|
@ -451,7 +447,7 @@ class StyleGuide:
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def add_diff_ranges(self, diffinfo: Dict[str, Set[int]]) -> None:
|
def add_diff_ranges(self, diffinfo: 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
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Utility methods for flake8."""
|
"""Utility methods for flake8."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import fnmatch as _fnmatch
|
import fnmatch as _fnmatch
|
||||||
import functools
|
import functools
|
||||||
|
|
@ -10,15 +12,9 @@ import re
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import tokenize
|
import tokenize
|
||||||
from typing import Dict
|
|
||||||
from typing import List
|
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Optional
|
|
||||||
from typing import Pattern
|
from typing import Pattern
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Set
|
|
||||||
from typing import Tuple
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
from flake8 import exceptions
|
from flake8 import exceptions
|
||||||
|
|
||||||
|
|
@ -30,7 +26,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.
|
||||||
|
|
||||||
:param value:
|
:param value:
|
||||||
|
|
@ -64,7 +60,7 @@ _FILE_LIST_TOKEN_TYPES = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def _tokenize_files_to_codes_mapping(value: str) -> List[_Token]:
|
def _tokenize_files_to_codes_mapping(value: str) -> list[_Token]:
|
||||||
tokens = []
|
tokens = []
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(value):
|
while i < len(value):
|
||||||
|
|
@ -82,8 +78,8 @@ def _tokenize_files_to_codes_mapping(value: str) -> List[_Token]:
|
||||||
|
|
||||||
|
|
||||||
def parse_files_to_codes_mapping( # noqa: C901
|
def parse_files_to_codes_mapping( # noqa: C901
|
||||||
value_: Union[Sequence[str], str]
|
value_: Sequence[str] | str,
|
||||||
) -> List[Tuple[str, List[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
|
||||||
|
|
@ -97,15 +93,15 @@ def parse_files_to_codes_mapping( # noqa: C901
|
||||||
else:
|
else:
|
||||||
value = value_
|
value = value_
|
||||||
|
|
||||||
ret: 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: List[str] = []
|
filenames: list[str] = []
|
||||||
codes: List[str] = []
|
codes: list[str] = []
|
||||||
|
|
||||||
def _reset() -> None:
|
def _reset() -> None:
|
||||||
if State.codes:
|
if State.codes:
|
||||||
|
|
@ -157,7 +153,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.
|
||||||
|
|
||||||
:returns:
|
:returns:
|
||||||
|
|
@ -201,12 +197,12 @@ def stdin_get_value() -> str:
|
||||||
return stdin_value.decode("utf-8")
|
return stdin_value.decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
def stdin_get_lines() -> List[str]:
|
def stdin_get_lines() -> list[str]:
|
||||||
"""Return lines of stdin split according to file splitting."""
|
"""Return lines of stdin split according to file splitting."""
|
||||||
return list(io.StringIO(stdin_get_value()))
|
return list(io.StringIO(stdin_get_value()))
|
||||||
|
|
||||||
|
|
||||||
def parse_unified_diff(diff: Optional[str] = None) -> Dict[str, Set[int]]:
|
def parse_unified_diff(diff: str | None = None) -> dict[str, set[int]]:
|
||||||
"""Parse the unified diff passed on stdin.
|
"""Parse the unified diff passed on stdin.
|
||||||
|
|
||||||
:returns:
|
:returns:
|
||||||
|
|
@ -218,7 +214,7 @@ def parse_unified_diff(diff: Optional[str] = None) -> Dict[str, Set[int]]:
|
||||||
|
|
||||||
number_of_rows = None
|
number_of_rows = None
|
||||||
current_path = None
|
current_path = None
|
||||||
parsed_paths: Dict[str, Set[int]] = collections.defaultdict(set)
|
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:
|
||||||
if not line or line[0] != "-":
|
if not line or line[0] != "-":
|
||||||
|
|
@ -271,7 +267,7 @@ def parse_unified_diff(diff: Optional[str] = None) -> Dict[str, Set[int]]:
|
||||||
return parsed_paths
|
return parsed_paths
|
||||||
|
|
||||||
|
|
||||||
def is_using_stdin(paths: List[str]) -> bool:
|
def is_using_stdin(paths: list[str]) -> bool:
|
||||||
"""Determine if we're going to read from stdin.
|
"""Determine if we're going to read from stdin.
|
||||||
|
|
||||||
:param paths:
|
:param paths:
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
"""Contains the Violation error class used internally."""
|
"""Contains the Violation error class used internally."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import linecache
|
import linecache
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict
|
|
||||||
from typing import Match
|
from typing import Match
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Optional
|
|
||||||
from typing import Set
|
|
||||||
|
|
||||||
from flake8 import defaults
|
from flake8 import defaults
|
||||||
from flake8 import utils
|
from flake8 import utils
|
||||||
|
|
@ -16,7 +15,7 @@ LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@functools.lru_cache(maxsize=512)
|
@functools.lru_cache(maxsize=512)
|
||||||
def _find_noqa(physical_line: str) -> Optional[Match[str]]:
|
def _find_noqa(physical_line: str) -> Match[str] | None:
|
||||||
return defaults.NOQA_INLINE_REGEXP.search(physical_line)
|
return defaults.NOQA_INLINE_REGEXP.search(physical_line)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -28,7 +27,7 @@ class Violation(NamedTuple):
|
||||||
line_number: int
|
line_number: int
|
||||||
column_number: int
|
column_number: int
|
||||||
text: str
|
text: str
|
||||||
physical_line: Optional[str]
|
physical_line: str | None
|
||||||
|
|
||||||
def is_inline_ignored(self, disable_noqa: bool) -> bool:
|
def is_inline_ignored(self, disable_noqa: bool) -> bool:
|
||||||
"""Determine if a comment has been added to ignore this line.
|
"""Determine if a comment has been added to ignore this line.
|
||||||
|
|
@ -69,7 +68,7 @@ class Violation(NamedTuple):
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def is_in(self, diff: Dict[str, Set[int]]) -> bool:
|
def is_in(self, diff: 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
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
"""This is here because mypy doesn't understand PEP 420."""
|
"""This is here because mypy doesn't understand PEP 420."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Test configuration for py.test."""
|
"""Test configuration for py.test."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import flake8
|
import flake8
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""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."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
class ExtensionTestPlugin2:
|
class ExtensionTestPlugin2:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Test aggregation of config files and command-line options."""
|
"""Test aggregation of config files and command-line options."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Integration tests for the legacy api."""
|
"""Integration tests for the legacy api."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from flake8.api import legacy
|
from flake8.api import legacy
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Integration tests for the checker submodule."""
|
"""Integration tests for the checker submodule."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Integration tests for the main entrypoint of flake8."""
|
"""Integration tests for the main entrypoint of flake8."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Integration tests for plugin loading."""
|
"""Integration tests for plugin loading."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8.main.cli import main
|
from flake8.main.cli import main
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Shared fixtures between unit tests."""
|
"""Shared fixtures between unit tests."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import configparser
|
import configparser
|
||||||
import sys
|
import sys
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import importlib.machinery
|
import importlib.machinery
|
||||||
import importlib.util
|
import importlib.util
|
||||||
import os.path
|
import os.path
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for the Application class."""
|
"""Tests for the Application class."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for the BaseFormatter object."""
|
"""Tests for the BaseFormatter object."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for the Manager object for FileCheckers."""
|
"""Tests for the Manager object for FileCheckers."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from flake8._compat import importlib_metadata
|
from flake8._compat import importlib_metadata
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for the flake8.style_guide.DecisionEngine class."""
|
"""Tests for the flake8.style_guide.DecisionEngine class."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for the flake8.exceptions module."""
|
"""Tests for the flake8.exceptions module."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Unit tests for the FileChecker class."""
|
"""Unit tests for the FileChecker class."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for the FileProcessor class."""
|
"""Tests for the FileProcessor class."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
import tokenize
|
import tokenize
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for the FilenameOnly formatter object."""
|
"""Tests for the FilenameOnly formatter object."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from flake8.formatting import default
|
from flake8.formatting import default
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for Flake8's legacy API."""
|
"""Tests for Flake8's legacy API."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import configparser
|
import configparser
|
||||||
import os.path
|
import os.path
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from flake8.main import options
|
from flake8.main import options
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for the Nothing formatter obbject."""
|
"""Tests for the Nothing formatter obbject."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from flake8.formatting import default
|
from flake8.formatting import default
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Unit tests for flake8.options.manager.Option."""
|
"""Unit tests for flake8.options.manager.Option."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Unit tests for flake.options.manager.OptionManager."""
|
"""Unit tests for flake.options.manager.OptionManager."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import configparser
|
import configparser
|
||||||
import os.path
|
import os.path
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests of pyflakes monkey patches."""
|
"""Tests of pyflakes monkey patches."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
import pyflakes
|
import pyflakes
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for the statistics module in Flake8."""
|
"""Tests for the statistics module in Flake8."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from flake8 import statistics as stats
|
from flake8 import statistics as stats
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for the flake8.style_guide.StyleGuide class."""
|
"""Tests for the flake8.style_guide.StyleGuide class."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for flake8's utils module."""
|
"""Tests for flake8's utils module."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for the flake8.violation.Violation class."""
|
"""Tests for the flake8.violation.Violation class."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
|
||||||
2
tox.ini
2
tox.ini
|
|
@ -1,6 +1,6 @@
|
||||||
[tox]
|
[tox]
|
||||||
minversion=2.3.1
|
minversion=2.3.1
|
||||||
envlist = py36,py37,py38,flake8,linters,docs
|
envlist = py37,py38,flake8,linters,docs
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
deps =
|
deps =
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue