Merge pull request #1633 from PyCQA/py37-plus

require python>=3.7
This commit is contained in:
Anthony Sottile 2022-08-27 20:34:38 -04:00 committed by GitHub
commit a929f124c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
76 changed files with 337 additions and 263 deletions

View file

@ -15,9 +15,6 @@ jobs:
- os: ubuntu-latest
python: pypy-3.7
toxenv: py
- os: ubuntu-latest
python: 3.6
toxenv: py
- os: ubuntu-latest
python: 3.7
toxenv: py
@ -32,7 +29,7 @@ jobs:
toxenv: py
# windows
- os: windows-latest
python: 3.6
python: 3.7
toxenv: py
# misc
- os: ubuntu-latest

View file

@ -11,12 +11,16 @@ repos:
rev: v3.8.2
hooks:
- 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
rev: v2.37.3
hooks:
- id: pyupgrade
args: [--py36-plus]
args: [--py37-plus]
- repo: https://github.com/psf/black
rev: 22.6.0
hooks:

View file

@ -1,11 +1,12 @@
#!/usr/bin/env python3
from __future__ import annotations
import inspect
import os.path
from typing import Any
from typing import Callable
from typing import Generator
from typing import NamedTuple
from typing import Tuple
import pycodestyle
@ -20,7 +21,7 @@ def _too_long(s: str) -> str:
class Call(NamedTuple):
name: str
is_generator: bool
params: Tuple[str, ...]
params: tuple[str, ...]
def to_src(self) -> str:
params_s = ", ".join(self.params)
@ -35,7 +36,7 @@ class Call(NamedTuple):
return "\n".join(lines)
@classmethod
def from_func(cls, func: Callable[..., Any]) -> "Call":
def from_func(cls, func: Callable[..., Any]) -> Call:
spec = inspect.getfullargspec(func)
params = tuple(spec.args)
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 "# fmt: off"
yield "from __future__ import annotations"
yield ""
yield "from typing import Any"
yield "from typing import Generator"
yield "from typing import Tuple"
yield ""
imports = sorted(call.name for call in logical + physical)
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}
for param in sorted(logical_params):
yield f" {param}: Any,"
yield ") -> Generator[Tuple[int, str], None, None]:"
yield ") -> Generator[tuple[int, str], None, None]:"
yield ' """Run pycodestyle logical checks."""'
for call in sorted(logical):
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}
for param in sorted(physical_params):
yield f" {param}: Any,"
yield ") -> Generator[Tuple[int, str], None, None]:"
yield ") -> Generator[tuple[int, str], None, None]:"
yield ' """Run pycodestyle physical checks."""'
for call in sorted(physical):
yield call.to_src()

View file

@ -14,6 +14,8 @@
# 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.
# sys.path.insert(0, os.path.abspath('.'))
from __future__ import annotations
import flake8
# -- General configuration ------------------------------------------------

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import setuptools
setuptools.setup(

View file

@ -1,4 +1,6 @@
"""Module for an example Flake8 plugin."""
from __future__ import annotations
from .off_by_default import ExampleTwo
from .on_by_default import ExampleOne

View file

@ -1,4 +1,5 @@
"""Our first example plugin."""
from __future__ import annotations
class ExampleTwo:

View file

@ -1,4 +1,5 @@
"""Our first example plugin."""
from __future__ import annotations
class ExampleOne:

View file

@ -20,7 +20,6 @@ classifiers =
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
@ -43,7 +42,7 @@ install_requires =
pycodestyle>=2.9.0,<2.10.0
pyflakes>=2.5.0,<2.6.0
importlib-metadata>=1.1.0,<4.3;python_version<"3.8"
python_requires = >=3.6.1
python_requires = >=3.7
[options.packages.find]
where = src

View file

@ -1,4 +1,6 @@
"""Packaging logic for Flake8."""
from __future__ import annotations
import os
import sys

View file

@ -9,10 +9,10 @@ This module
.. autofunction:: flake8.configure_logging
"""
from __future__ import annotations
import logging
import sys
from typing import Optional
from typing import Type
LOG = logging.getLogger(__name__)
LOG.addHandler(logging.NullHandler())
@ -35,7 +35,7 @@ LOG_FORMAT = (
def configure_logging(
verbosity: int,
filename: Optional[str] = None,
filename: str | None = None,
logformat: str = LOG_FORMAT,
) -> None:
"""Configure logging for flake8.
@ -56,7 +56,7 @@ def configure_logging(
if not filename or filename in ("stderr", "stdout"):
fileobj = getattr(sys, filename or "stderr")
handler_cls: Type[logging.Handler] = logging.StreamHandler
handler_cls: type[logging.Handler] = logging.StreamHandler
else:
fileobj = filename
handler_cls = logging.FileHandler

View file

@ -1,4 +1,6 @@
"""Module allowing for ``python -m flake8 ...``."""
from __future__ import annotations
from flake8.main.cli import main
if __name__ == "__main__":

View file

@ -1,4 +1,6 @@
"""Expose backports in a single place."""
from __future__ import annotations
import sys
if sys.version_info >= (3, 8): # pragma: no cover (PY38+)

View file

@ -3,3 +3,4 @@
This is the only submodule in Flake8 with a guaranteed stable API. All other
submodules are considered internal only and are subject to change.
"""
from __future__ import annotations

View file

@ -3,13 +3,12 @@
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.
"""
from __future__ import annotations
import argparse
import logging
import os.path
from typing import Any
from typing import List
from typing import Optional
from typing import Type
import flake8
from flake8.discover_files import expand_paths
@ -53,7 +52,7 @@ class Report:
"""Return the total number of errors."""
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.
:returns:
@ -97,12 +96,12 @@ class StyleGuide:
return self._application.options
@property
def paths(self) -> List[str]:
def paths(self) -> list[str]:
"""Return the extra arguments passed as paths."""
assert self._application.options is not None
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.
This will check the files passed in and return a :class:`Report`
@ -119,7 +118,7 @@ class StyleGuide:
self._application.report_errors()
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.
:param filename:
@ -148,7 +147,7 @@ class StyleGuide:
def init_report(
self,
reporter: Optional[Type[formatter.BaseFormatter]] = None,
reporter: type[formatter.BaseFormatter] | None = None,
) -> None:
"""Set up a formatter for this run of Flake8."""
if reporter is None:
@ -170,9 +169,9 @@ class StyleGuide:
def input_file(
self,
filename: str,
lines: Optional[Any] = None,
expected: Optional[Any] = None,
line_offset: Optional[Any] = 0,
lines: Any | None = None,
expected: Any | None = None,
line_offset: Any | None = 0,
) -> Report:
"""Run collected checks on a single file.

View file

@ -1,4 +1,6 @@
"""Checker Manager and Checker classes."""
from __future__ import annotations
import argparse
import collections
import errno
@ -8,7 +10,6 @@ import multiprocessing.pool
import signal
import tokenize
from typing import Any
from typing import Dict
from typing import List
from typing import Optional
from typing import Tuple
@ -71,8 +72,8 @@ class Manager:
self.options = style_guide.options
self.plugins = plugins
self.jobs = self._job_count()
self._all_checkers: List[FileChecker] = []
self.checkers: List[FileChecker] = []
self._all_checkers: list[FileChecker] = []
self.checkers: list[FileChecker] = []
self.statistics = {
"files": 0,
"logical lines": 0,
@ -152,7 +153,7 @@ class Manager:
)
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."""
if paths is None:
paths = self.options.filenames
@ -174,7 +175,7 @@ class Manager:
self.checkers = [c for c in self._all_checkers if c.should_process]
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.
This iterates over each of the checkers and reports the errors sorted
@ -195,8 +196,8 @@ class Manager:
def run_parallel(self) -> None:
"""Run the checkers in parallel."""
# fmt: off
final_results: Dict[str, List[Tuple[str, int, int, str, Optional[str]]]] = collections.defaultdict(list) # noqa: E501
final_statistics: Dict[str, Dict[str, int]] = collections.defaultdict(dict) # 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
# fmt: on
pool = _try_initialize_processpool(self.jobs)
@ -254,7 +255,7 @@ class Manager:
LOG.warning("Flake8 was interrupted by the user")
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.
:param paths:
@ -301,7 +302,7 @@ class FileChecker:
"""Provide helpful debugging representation."""
return f"FileChecker for {self.filename}"
def _make_processor(self) -> Optional[processor.FileProcessor]:
def _make_processor(self) -> processor.FileProcessor | None:
try:
return processor.FileProcessor(self.filename, self.options)
except OSError as e:
@ -316,7 +317,7 @@ class FileChecker:
def report(
self,
error_code: Optional[str],
error_code: str | None,
line_number: int,
column: int,
text: str,
@ -361,7 +362,7 @@ class FileChecker:
)
@staticmethod
def _extract_syntax_information(exception: Exception) -> Tuple[int, int]:
def _extract_syntax_information(exception: Exception) -> tuple[int, int]:
if (
len(exception.args) > 1
and exception.args[1]
@ -524,7 +525,7 @@ class FileChecker:
self.run_physical_checks(file_processor.lines[-1])
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."""
assert self.processor is not None
try:
@ -592,7 +593,7 @@ def _pool_init() -> None:
def _try_initialize_processpool(
job_count: int,
) -> Optional[multiprocessing.pool.Pool]:
) -> multiprocessing.pool.Pool | None:
"""Return a new process pool instance if we are able to create one."""
try:
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)
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()
def find_offset(
offset: int, mapping: processor._LogicalMapping
) -> Tuple[int, int]:
) -> tuple[int, int]:
"""Find the offset tuple for a single offset."""
if isinstance(offset, tuple):
return offset

View file

@ -1,4 +1,6 @@
"""Constants that define defaults."""
from __future__ import annotations
import re
EXCLUDE = (

View file

@ -1,4 +1,6 @@
"""Functions related to discovering paths."""
from __future__ import annotations
import logging
import os.path
from typing import Callable

View file

@ -1,4 +1,5 @@
"""Exception classes for all of Flake8."""
from __future__ import annotations
class Flake8Exception(Exception):

View file

@ -1 +1,2 @@
"""Submodule containing the default formatters for Flake8."""
from __future__ import annotations

View file

@ -2,6 +2,8 @@
See: https://github.com/pre-commit/pre-commit/blob/cb40e96/pre_commit/color.py
"""
from __future__ import annotations
import sys
if sys.platform == "win32": # pragma: no cover (windows)

View file

@ -1,11 +1,10 @@
"""The base class and interface for all formatting plugins."""
from __future__ import annotations
import argparse
import os
import sys
from typing import IO
from typing import List
from typing import Optional
from typing import Tuple
from flake8.formatting import _windows_color
from flake8.statistics import Statistics
@ -46,7 +45,7 @@ class BaseFormatter:
"""
self.options = options
self.filename = options.output_file
self.output_fd: Optional[IO[str]] = None
self.output_fd: IO[str] | None = None
self.newline = "\n"
self.color = options.color == "always" or (
options.color == "auto"
@ -84,7 +83,7 @@ class BaseFormatter:
os.makedirs(dirname, exist_ok=True)
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.
This defaults to calling :meth:`format`, :meth:`show_source`, and
@ -99,7 +98,7 @@ class BaseFormatter:
source = self.show_source(error)
self.write(line, source)
def format(self, error: "Violation") -> Optional[str]:
def format(self, error: Violation) -> str | None:
"""Format an error reported by Flake8.
This method **must** be implemented by subclasses.
@ -114,7 +113,7 @@ class BaseFormatter:
"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."""
for error_code in statistics.error_codes():
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)
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."""
# NOTE(sigmavirus24): The format strings are a little confusing, even
# to me, so here's a quick explanation:
@ -144,7 +143,7 @@ class BaseFormatter:
benchmark = float_format(statistic=statistic, value=value)
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.
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:
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.
This handles deciding whether to write to a file or print to standard

View file

@ -1,6 +1,5 @@
"""Default formatting class for Flake8."""
from typing import Optional
from typing import Set
from __future__ import annotations
from flake8.formatting import base
from flake8.violation import Violation
@ -38,7 +37,7 @@ class SimpleFormatter(base.BaseFormatter):
error_format: str
def format(self, error: "Violation") -> Optional[str]:
def format(self, error: Violation) -> str | None:
"""Format and write error out.
If an output filename is specified, write formatted errors to that
@ -86,12 +85,12 @@ class FilenameOnly(SimpleFormatter):
def after_init(self) -> None:
"""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."""
def format(self, error: "Violation") -> Optional[str]:
def format(self, error: Violation) -> str | None:
"""Ensure we only print each error once."""
if error.filename not in self.filenames_already_printed:
self.filenames_already_printed.add(error.filename)
@ -103,8 +102,8 @@ class FilenameOnly(SimpleFormatter):
class Nothing(base.BaseFormatter):
"""Print absolutely nothing."""
def format(self, error: "Violation") -> Optional[str]:
def format(self, error: Violation) -> str | None:
"""Do nothing."""
def show_source(self, error: "Violation") -> Optional[str]:
def show_source(self, error: Violation) -> str | None:
"""Do not print the source."""

View file

@ -1 +1,2 @@
"""Module containing the logic for the Flake8 entry-points."""
from __future__ import annotations

View file

@ -1,15 +1,12 @@
"""Module containing the application logic for Flake8."""
from __future__ import annotations
import argparse
import configparser
import json
import logging
import time
from typing import Dict
from typing import List
from typing import Optional
from typing import Sequence
from typing import Set
from typing import Tuple
import flake8
from flake8 import checker
@ -38,27 +35,27 @@ class Application:
#: The timestamp when the Application instance was instantiated.
self.start_time = time.time()
#: 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
#: obtaining and parsing the configuration file.
self.prelim_arg_parser = options.stage1_arg_parser()
#: The instance of :class:`flake8.options.manager.OptionManager` used
#: 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`
self.formatter: Optional[BaseFormatter] = None
self.formatter: BaseFormatter | None = None
#: The :class:`flake8.style_guide.StyleGuideManager` built from the
#: 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 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
#: :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
#: flake8 and taking into account ignored errors and lines.
self.result_count = 0
@ -70,11 +67,11 @@ class Application:
self.catastrophic_failure = False
#: The parsed diff information
self.parsed_diff: Dict[str, Set[int]] = {}
self.parsed_diff: dict[str, set[int]] = {}
def parse_preliminary_options(
self, argv: Sequence[str]
) -> Tuple[argparse.Namespace, List[str]]:
) -> tuple[argparse.Namespace, list[str]]:
"""Get preliminary options from the CLI, pre-plugin-loading.
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_dir: str,
*,
enable_extensions: Optional[str],
require_plugins: Optional[str],
enable_extensions: str | None,
require_plugins: str | None,
) -> None:
"""Find and load the plugins for this application.
@ -143,7 +140,7 @@ class Application:
self,
cfg: configparser.RawConfigParser,
cfg_dir: str,
argv: List[str],
argv: list[str],
) -> None:
"""Parse configuration files and the CLI options."""
assert self.option_manager is not None
@ -218,7 +215,7 @@ class Application:
assert self.options is not None
assert self.file_checker_manager is not None
if self.options.diff:
files: Optional[List[str]] = sorted(self.parsed_diff)
files: list[str] | None = sorted(self.parsed_diff)
if not files:
return
else:

View file

@ -1,12 +1,13 @@
"""Command-line implementation of flake8."""
from __future__ import annotations
import sys
from typing import Optional
from typing import Sequence
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.
This handles the creation of an instance of :class:`Application`, runs it,

View file

@ -1,12 +1,13 @@
"""Module containing the logic for our debugging logic."""
from __future__ import annotations
import platform
from typing import Any
from typing import Dict
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."""
versions = sorted(
{

View file

@ -1,4 +1,6 @@
"""Contains the logic for all of the default options for Flake8."""
from __future__ import annotations
import argparse
from flake8 import defaults

View file

@ -10,3 +10,4 @@
to aggregate configuration into one object used by plugins and Flake8.
"""
from __future__ import annotations

View file

@ -3,10 +3,11 @@
This holds the logic that uses the collected and merged config files and
applies the user-specified command-line configuration on top of it.
"""
from __future__ import annotations
import argparse
import configparser
import logging
from typing import Optional
from typing import Sequence
from flake8.options import config
@ -19,7 +20,7 @@ def aggregate_options(
manager: OptionManager,
cfg: configparser.RawConfigParser,
cfg_dir: str,
argv: Optional[Sequence[str]],
argv: Sequence[str] | None,
) -> argparse.Namespace:
"""Aggregate and merge CLI and config file options."""
# Get defaults from the option parser

View file

@ -1,12 +1,10 @@
"""Config handling logic for Flake8."""
from __future__ import annotations
import configparser
import logging
import os.path
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.options.manager import OptionManager
@ -14,13 +12,13 @@ from flake8.options.manager import OptionManager
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
st = os.stat(s)
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 `~`
home = os.path.expanduser("~")
try:
@ -55,11 +53,11 @@ def _find_config_file(path: str) -> Optional[str]:
def load_config(
config: Optional[str],
extra: List[str],
config: str | None,
extra: list[str],
*,
isolated: bool = False,
) -> Tuple[configparser.RawConfigParser, str]:
) -> tuple[configparser.RawConfigParser, str]:
"""Load the configuration given the user options.
- in ``isolated`` mode, return an empty configuration
@ -97,7 +95,7 @@ def parse_config(
option_manager: OptionManager,
cfg: configparser.RawConfigParser,
cfg_dir: str,
) -> Dict[str, Any]:
) -> dict[str, Any]:
"""Parse and normalize the typed configuration options."""
if "flake8" not in cfg:
return {}

View file

@ -1,18 +1,14 @@
"""Option handling and Option management logic."""
from __future__ import annotations
import argparse
import enum
import functools
import logging
from typing import Any
from typing import Callable
from typing import Dict
from typing import List
from typing import Mapping
from typing import Optional
from typing import Sequence
from typing import Tuple
from typing import Type
from typing import Union
from flake8 import utils
from flake8.plugins.finder import Plugins
@ -24,7 +20,7 @@ LOG = logging.getLogger(__name__)
_ARG = enum.Enum("_ARG", "NO")
_optparse_callable_map: Dict[str, Union[Type[Any], _ARG]] = {
_optparse_callable_map: dict[str, type[Any] | _ARG] = {
"int": int,
"long": int,
"string": str,
@ -44,7 +40,7 @@ class _CallbackAction(argparse.Action):
*args: Any,
callback: Callable[..., Any],
callback_args: Sequence[Any] = (),
callback_kwargs: Optional[Dict[str, Any]] = None,
callback_kwargs: dict[str, Any] | None = None,
**kwargs: Any,
) -> None:
self._callback = callback
@ -56,8 +52,8 @@ class _CallbackAction(argparse.Action):
self,
parser: argparse.ArgumentParser,
namespace: argparse.Namespace,
values: Optional[Union[Sequence[str], str]],
option_string: Optional[str] = None,
values: Sequence[str] | str | None,
option_string: str | None = None,
) -> None:
if not values:
values = None
@ -78,8 +74,8 @@ def _flake8_normalize(
*args: str,
comma_separated_list: bool = False,
normalize_paths: bool = False,
) -> Union[str, List[str]]:
ret: Union[str, List[str]] = value
) -> str | list[str]:
ret: str | list[str] = value
if comma_separated_list and isinstance(ret, str):
ret = utils.parse_comma_separated_list(value)
@ -97,24 +93,24 @@ class Option:
def __init__(
self,
short_option_name: Union[str, _ARG] = _ARG.NO,
long_option_name: Union[str, _ARG] = _ARG.NO,
short_option_name: str | _ARG = _ARG.NO,
long_option_name: str | _ARG = _ARG.NO,
# Options below here are taken from the optparse.Option class
action: Union[str, Type[argparse.Action], _ARG] = _ARG.NO,
default: Union[Any, _ARG] = _ARG.NO,
type: Union[str, Callable[..., Any], _ARG] = _ARG.NO,
dest: Union[str, _ARG] = _ARG.NO,
nargs: Union[int, str, _ARG] = _ARG.NO,
const: Union[Any, _ARG] = _ARG.NO,
choices: Union[Sequence[Any], _ARG] = _ARG.NO,
help: Union[str, _ARG] = _ARG.NO,
metavar: Union[str, _ARG] = _ARG.NO,
action: str | type[argparse.Action] | _ARG = _ARG.NO,
default: Any | _ARG = _ARG.NO,
type: str | Callable[..., Any] | _ARG = _ARG.NO,
dest: str | _ARG = _ARG.NO,
nargs: int | str | _ARG = _ARG.NO,
const: Any | _ARG = _ARG.NO,
choices: Sequence[Any] | _ARG = _ARG.NO,
help: str | _ARG = _ARG.NO,
metavar: str | _ARG = _ARG.NO,
# deprecated optparse-only options
callback: Union[Callable[..., Any], _ARG] = _ARG.NO,
callback_args: Union[Sequence[Any], _ARG] = _ARG.NO,
callback_kwargs: Union[Mapping[str, Any], _ARG] = _ARG.NO,
callback: Callable[..., Any] | _ARG = _ARG.NO,
callback_args: Sequence[Any] | _ARG = _ARG.NO,
callback_kwargs: Mapping[str, Any] | _ARG = _ARG.NO,
# 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
parse_from_config: bool = False,
comma_separated_list: bool = False,
@ -247,7 +243,7 @@ class Option:
self.help = help
self.metavar = metavar
self.required = required
self.option_kwargs: Dict[str, Union[Any, _ARG]] = {
self.option_kwargs: dict[str, Any | _ARG] = {
"action": self.action,
"default": self.default,
"type": self.type,
@ -268,7 +264,7 @@ class Option:
self.comma_separated_list = comma_separated_list
self.normalize_paths = normalize_paths
self.config_name: Optional[str] = None
self.config_name: str | None = None
if parse_from_config:
if long_option_name is _ARG.NO:
raise ValueError(
@ -280,7 +276,7 @@ class Option:
self._opt = None
@property
def filtered_option_kwargs(self) -> Dict[str, Any]:
def filtered_option_kwargs(self) -> dict[str, Any]:
"""Return any actually-specified arguments."""
return {
k: v for k, v in self.option_kwargs.items() if v is not _ARG.NO
@ -307,7 +303,7 @@ class Option:
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."""
return self.option_args, self.filtered_option_kwargs
@ -320,7 +316,7 @@ class OptionManager:
*,
version: str,
plugin_versions: str,
parents: List[argparse.ArgumentParser],
parents: list[argparse.ArgumentParser],
) -> None:
"""Initialize an instance of an OptionManager.
@ -350,17 +346,17 @@ class OptionManager:
)
self.parser.add_argument("filenames", nargs="*", metavar="filename")
self.config_options_dict: Dict[str, Option] = {}
self.options: List[Option] = []
self.extended_default_ignore: List[str] = []
self.extended_default_select: List[str] = []
self.config_options_dict: dict[str, Option] = {}
self.options: list[Option] = []
self.extended_default_ignore: 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
def register_plugins(self, plugins: Plugins) -> None:
"""Register the plugin options (if needed)."""
groups: Dict[str, argparse._ArgumentGroup] = {}
groups: dict[str, argparse._ArgumentGroup] = {}
def _set_group(name: str) -> None:
try:
@ -428,8 +424,8 @@ class OptionManager:
def parse_args(
self,
args: Optional[Sequence[str]] = None,
values: Optional[argparse.Namespace] = None,
args: Sequence[str] | None = None,
values: argparse.Namespace | None = None,
) -> argparse.Namespace:
"""Proxy to calling the OptionParser's parse_args method."""
if values:

View file

@ -1 +1,2 @@
"""Submodule of built-in plugins and plugin managers."""
from __future__ import annotations

View file

@ -1,4 +1,6 @@
"""Functions related to finding and loading plugins."""
from __future__ import annotations
import configparser
import inspect
import itertools
@ -6,14 +8,9 @@ import logging
import re
import sys
from typing import Any
from typing import Dict
from typing import FrozenSet
from typing import Generator
from typing import Iterable
from typing import List
from typing import NamedTuple
from typing import Optional
from typing import Tuple
from flake8 import utils
from flake8._compat import importlib_metadata
@ -45,7 +42,7 @@ class LoadedPlugin(NamedTuple):
plugin: Plugin
obj: Any
parameters: Dict[str, bool]
parameters: dict[str, bool]
@property
def entry_name(self) -> str:
@ -61,17 +58,17 @@ class LoadedPlugin(NamedTuple):
class Checkers(NamedTuple):
"""Classified plugins needed for checking."""
tree: List[LoadedPlugin]
logical_line: List[LoadedPlugin]
physical_line: List[LoadedPlugin]
tree: list[LoadedPlugin]
logical_line: list[LoadedPlugin]
physical_line: list[LoadedPlugin]
class Plugins(NamedTuple):
"""Classified plugins."""
checkers: Checkers
reporters: Dict[str, LoadedPlugin]
disabled: List[LoadedPlugin]
reporters: dict[str, LoadedPlugin]
disabled: list[LoadedPlugin]
def all_plugins(self) -> Generator[LoadedPlugin, None, None]:
"""Return an iterator over all :class:`LoadedPlugin`s."""
@ -96,12 +93,12 @@ class Plugins(NamedTuple):
class PluginOptions(NamedTuple):
"""Options related to plugin loading."""
local_plugin_paths: Tuple[str, ...]
enable_extensions: FrozenSet[str]
require_plugins: FrozenSet[str]
local_plugin_paths: tuple[str, ...]
enable_extensions: frozenset[str]
require_plugins: frozenset[str]
@classmethod
def blank(cls) -> "PluginOptions":
def blank(cls) -> PluginOptions:
"""Make a blank PluginOptions, mostly used for tests."""
return cls(
local_plugin_paths=(),
@ -113,8 +110,8 @@ class PluginOptions(NamedTuple):
def _parse_option(
cfg: configparser.RawConfigParser,
cfg_opt_name: str,
opt: Optional[str],
) -> List[str]:
opt: str | None,
) -> list[str]:
# specified on commandline: use that
if opt is not None:
return utils.parse_comma_separated_list(opt)
@ -133,8 +130,8 @@ def parse_plugin_options(
cfg: configparser.RawConfigParser,
cfg_dir: str,
*,
enable_extensions: Optional[str],
require_plugins: Optional[str],
enable_extensions: str | None,
require_plugins: str | None,
) -> PluginOptions:
"""Parse plugin loading related options."""
paths_s = cfg.get("flake8:local-plugins", "paths", fallback="").strip()
@ -231,8 +228,8 @@ def _find_local_plugins(
def _check_required_plugins(
plugins: List[Plugin],
expected: FrozenSet[str],
plugins: list[Plugin],
expected: frozenset[str],
) -> None:
plugin_names = {
utils.normalize_pypi_name(plugin.package) for plugin in plugins
@ -252,7 +249,7 @@ def _check_required_plugins(
def find_plugins(
cfg: configparser.RawConfigParser,
opts: PluginOptions,
) -> List[Plugin]:
) -> list[Plugin]:
"""Discovers all plugins (but does not load them)."""
ret = [*_find_importlib_plugins(), *_find_local_plugins(cfg)]
@ -264,7 +261,7 @@ def find_plugins(
return ret
def _parameters_for(func: Any) -> Dict[str, bool]:
def _parameters_for(func: Any) -> dict[str, bool]:
"""Return the parameters for the plugin.
This will inspect the plugin and return either the function parameters
@ -305,15 +302,15 @@ def _load_plugin(plugin: Plugin) -> LoadedPlugin:
def _import_plugins(
plugins: List[Plugin],
plugins: list[Plugin],
opts: PluginOptions,
) -> List[LoadedPlugin]:
) -> list[LoadedPlugin]:
sys.path.extend(opts.local_plugin_paths)
return [_load_plugin(p) for p in plugins]
def _classify_plugins(
plugins: List[LoadedPlugin],
plugins: list[LoadedPlugin],
opts: PluginOptions,
) -> Plugins:
tree = []
@ -358,7 +355,7 @@ def _classify_plugins(
def load_plugins(
plugins: List[Plugin],
plugins: list[Plugin],
opts: PluginOptions,
) -> Plugins:
"""Load and classify all flake8 plugins.

View file

@ -1,8 +1,9 @@
"""Generated using ./bin/gen-pycodestyle-plugin."""
# fmt: off
from __future__ import annotations
from typing import Any
from typing import Generator
from typing import Tuple
from pycodestyle import ambiguous_identifier as _ambiguous_identifier
from pycodestyle import bare_except as _bare_except
@ -60,7 +61,7 @@ def pycodestyle_logical(
previous_unindented_logical_line: Any,
tokens: Any,
verbose: Any,
) -> Generator[Tuple[int, str], None, None]:
) -> Generator[tuple[int, str], None, None]:
"""Run pycodestyle logical checks."""
yield from _ambiguous_identifier(logical_line, tokens)
yield from _bare_except(logical_line, noqa)
@ -104,7 +105,7 @@ def pycodestyle_physical(
noqa: Any,
physical_line: Any,
total_lines: Any,
) -> Generator[Tuple[int, str], None, None]:
) -> Generator[tuple[int, str], None, None]:
"""Run pycodestyle physical checks."""
ret = _maximum_line_length(physical_line, max_line_length, multiline, line_number, noqa) # noqa: E501
if ret is not None:

View file

@ -1,13 +1,12 @@
"""Plugin built-in to Flake8 to treat pyflakes as a plugin."""
from __future__ import annotations
import argparse
import ast
import os
import tokenize
from typing import Any
from typing import Generator
from typing import List
from typing import Tuple
from typing import Type
import pyflakes.checker
@ -68,13 +67,13 @@ class FlakesChecker(pyflakes.checker.Checker):
"""Subclass the Pyflakes checker to conform with the flake8 API."""
with_doctest = False
include_in_doctest: List[str] = []
exclude_from_doctest: List[str] = []
include_in_doctest: list[str] = []
exclude_from_doctest: list[str] = []
def __init__(
self,
tree: ast.AST,
file_tokens: List[tokenize.TokenInfo],
file_tokens: list[tokenize.TokenInfo],
filename: str,
) -> None:
"""Initialize the PyFlakes plugin with an AST tree and filename."""
@ -180,7 +179,7 @@ class FlakesChecker(pyflakes.checker.Checker):
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."""
for message in self.messages:
col = getattr(message, "col", 0)

View file

@ -1,7 +1,8 @@
"""Functions for construcing the requested report plugin."""
from __future__ import annotations
import argparse
import logging
from typing import Dict
from flake8.formatting.base import BaseFormatter
from flake8.plugins.finder import LoadedPlugin
@ -10,7 +11,7 @@ LOG = logging.getLogger(__name__)
def make(
reporters: Dict[str, LoadedPlugin],
reporters: dict[str, LoadedPlugin],
options: argparse.Namespace,
) -> BaseFormatter:
"""Make the formatter from the requested user options.

View file

@ -1,14 +1,14 @@
"""Module containing our file processor that tokenizes a file for checks."""
from __future__ import annotations
import argparse
import ast
import contextlib
import logging
import tokenize
from typing import Any
from typing import Dict
from typing import Generator
from typing import List
from typing import Optional
from typing import Tuple
from flake8 import defaults
@ -61,7 +61,7 @@ class FileProcessor:
self,
filename: str,
options: argparse.Namespace,
lines: Optional[List[str]] = None,
lines: list[str] | None = None,
) -> None:
"""Initialice our file processor.
@ -78,13 +78,13 @@ class FileProcessor:
#: Number of blank lines
self.blank_lines = 0
#: Checker states for each plugin?
self._checker_states: Dict[str, Dict[Any, Any]] = {}
self._checker_states: dict[str, dict[Any, Any]] = {}
#: Current checker state
self.checker_state: Dict[Any, Any] = {}
self.checker_state: dict[Any, Any] = {}
#: User provided option for hang closing
self.hang_closing = options.hang_closing
#: Character used for indentation
self.indent_char: Optional[str] = None
self.indent_char: str | None = None
#: Current level of indentation
self.indent_level = 0
#: Number of spaces used for indentation
@ -106,19 +106,19 @@ class FileProcessor:
#: Previous unindented (i.e. top-level) logical line
self.previous_unindented_logical_line = ""
#: Current set of tokens
self.tokens: List[tokenize.TokenInfo] = []
self.tokens: list[tokenize.TokenInfo] = []
#: Total number of lines in the file
self.total_lines = len(self.lines)
#: Verbosity level of Flake8
self.verbose = options.verbose
#: Statistics dictionary
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
self._noqa_line_mapping: Optional[Dict[int, str]] = None
self._noqa_line_mapping: dict[int, str] | None = None
@property
def file_tokens(self) -> List[tokenize.TokenInfo]:
def file_tokens(self) -> list[tokenize.TokenInfo]:
"""Return the complete set of tokens for a file."""
if self._file_tokens is None:
line_iter = iter(self.lines)
@ -217,7 +217,7 @@ class FileProcessor:
"""Build an abstract syntax tree from the list of 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."""
comments, logical, mapping_list = self.build_logical_line_tokens()
joined_comments = "".join(comments)
@ -240,9 +240,9 @@ class FileProcessor:
def keyword_arguments_for(
self,
parameters: Dict[str, bool],
arguments: Dict[str, Any],
) -> Dict[str, Any]:
parameters: dict[str, bool],
arguments: dict[str, Any],
) -> dict[str, Any]:
"""Generate the keyword arguments for a list of parameters."""
ret = {}
for param, required in parameters.items():
@ -269,12 +269,12 @@ class FileProcessor:
self.tokens.append(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)
joined = "".join(self.lines[min_line - 1 : max_line])
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."""
if self._noqa_line_mapping is None:
try:
@ -324,7 +324,7 @@ class FileProcessor:
self.indent_char = line[0]
return line
def read_lines(self) -> List[str]:
def read_lines(self) -> list[str]:
"""Read the lines for this file checker."""
if self.filename is None or self.filename == "-":
self.filename = self.options.stdin_display_name or "stdin"
@ -333,7 +333,7 @@ class FileProcessor:
lines = self.read_lines_from_filename()
return lines
def read_lines_from_filename(self) -> List[str]:
def read_lines_from_filename(self) -> list[str]:
"""Read the lines for a file."""
try:
with tokenize.open(self.filename) as fd:
@ -344,7 +344,7 @@ class FileProcessor:
with open(self.filename, encoding="latin-1") as fd:
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."""
return utils.stdin_get_lines()

View file

@ -1,9 +1,8 @@
"""Statistic collection logic for Flake8."""
from typing import Dict
from __future__ import annotations
from typing import Generator
from typing import List
from typing import NamedTuple
from typing import Optional
from flake8.violation import Violation
@ -13,9 +12,9 @@ class Statistics:
def __init__(self) -> None:
"""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.
:returns:
@ -23,7 +22,7 @@ class Statistics:
"""
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.
:param error:
@ -36,8 +35,8 @@ class Statistics:
self._store[key].increment()
def statistics_for(
self, prefix: str, filename: Optional[str] = None
) -> Generator["Statistic", None, None]:
self, prefix: str, filename: str | None = None
) -> Generator[Statistic, None, None]:
"""Generate statistics for the prefix and filename.
If you have a :class:`Statistics` object that has recorded errors,
@ -79,11 +78,11 @@ class Key(NamedTuple):
code: str
@classmethod
def create_from(cls, error: "Violation") -> "Key":
def create_from(cls, error: Violation) -> Key:
"""Create a Key from :class:`flake8.violation.Violation`."""
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.
:param prefix:
@ -118,7 +117,7 @@ class Statistic:
self.count = count
@classmethod
def create_from(cls, error: "Violation") -> "Statistic":
def create_from(cls, error: Violation) -> Statistic:
"""Create a Statistic from a :class:`flake8.violation.Violation`."""
return cls(
error_code=error.code,

View file

@ -1,4 +1,6 @@
"""Implementation of the StyleGuide used by Flake8."""
from __future__ import annotations
import argparse
import contextlib
import copy
@ -6,14 +8,8 @@ import enum
import functools
import itertools
import logging
from typing import Dict
from typing import Generator
from typing import List
from typing import Optional
from typing import Sequence
from typing import Set
from typing import Tuple
from typing import Union
from flake8 import defaults
from flake8 import statistics
@ -49,20 +45,20 @@ class Decision(enum.Enum):
def _explicitly_chosen(
*,
option: Optional[List[str]],
extend: Optional[List[str]],
) -> Tuple[str, ...]:
option: list[str] | None,
extend: list[str] | None,
) -> tuple[str, ...]:
ret = [*(option or []), *(extend or [])]
return tuple(sorted(ret, reverse=True))
def _select_ignore(
*,
option: Optional[List[str]],
default: Tuple[str, ...],
extended_default: List[str],
extend: Optional[List[str]],
) -> Tuple[str, ...]:
option: list[str] | None,
default: tuple[str, ...],
extended_default: list[str],
extend: list[str] | None,
) -> tuple[str, ...]:
# option was explicitly set, ignore the default and extended default
if option is not None:
ret = [*option, *(extend or [])]
@ -80,7 +76,7 @@ class DecisionEngine:
def __init__(self, options: argparse.Namespace) -> None:
"""Initialize the engine."""
self.cache: Dict[str, Decision] = {}
self.cache: dict[str, Decision] = {}
self.selected_explicitly = _explicitly_chosen(
option=options.select,
@ -104,7 +100,7 @@ class DecisionEngine:
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.
:param code: The code for the check that has been run.
@ -122,7 +118,7 @@ class DecisionEngine:
else:
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.
:param code:
@ -211,7 +207,7 @@ class StyleGuideManager:
self,
options: argparse.Namespace,
formatter: base_formatter.BaseFormatter,
decider: Optional[DecisionEngine] = None,
decider: DecisionEngine | None = None,
) -> None:
"""Initialize our StyleGuide.
@ -221,7 +217,7 @@ class StyleGuideManager:
self.formatter = formatter
self.stats = statistics.Statistics()
self.decider = decider or DecisionEngine(options)
self.style_guides: List[StyleGuide] = []
self.style_guides: list[StyleGuide] = []
self.default_style_guide = StyleGuide(
options, formatter, self.stats, decider=decider
)
@ -238,7 +234,7 @@ class StyleGuideManager:
def populate_style_guides_with(
self, options: argparse.Namespace
) -> Generator["StyleGuide", None, None]:
) -> Generator[StyleGuide, None, None]:
"""Generate style guides from the per-file-ignores option.
:param options:
@ -252,7 +248,7 @@ class StyleGuideManager:
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."""
return max(
(g for g in self.style_guides if g.applies_to(filename)),
@ -262,7 +258,7 @@ class StyleGuideManager:
@contextlib.contextmanager
def processing_file(
self, filename: str
) -> Generator["StyleGuide", None, None]:
) -> Generator[StyleGuide, None, None]:
"""Record the fact that we're processing the file's results."""
guide = self.style_guide_for(filename)
with guide.processing_file(filename):
@ -275,7 +271,7 @@ class StyleGuideManager:
line_number: int,
column_number: int,
text: str,
physical_line: Optional[str] = None,
physical_line: str | None = None,
) -> int:
"""Handle an error reported by a check.
@ -302,7 +298,7 @@ class StyleGuideManager:
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.
This provides information to the underlying StyleGuides so that only
@ -323,8 +319,8 @@ class StyleGuide:
options: argparse.Namespace,
formatter: base_formatter.BaseFormatter,
stats: statistics.Statistics,
filename: Optional[str] = None,
decider: Optional[DecisionEngine] = None,
filename: str | None = None,
decider: DecisionEngine | None = None,
):
"""Initialize our StyleGuide.
@ -337,7 +333,7 @@ class StyleGuide:
self.filename = filename
if 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:
"""Make it easier to debug which StyleGuide we're using."""
@ -345,9 +341,9 @@ class StyleGuide:
def copy(
self,
filename: Optional[str] = None,
extend_ignore_with: Optional[Sequence[str]] = None,
) -> "StyleGuide":
filename: str | None = None,
extend_ignore_with: Sequence[str] | None = None,
) -> StyleGuide:
"""Create a copy of this style guide with different values."""
filename = filename or self.filename
options = copy.deepcopy(self.options)
@ -360,7 +356,7 @@ class StyleGuide:
@contextlib.contextmanager
def processing_file(
self, filename: str
) -> Generator["StyleGuide", None, None]:
) -> Generator[StyleGuide, None, None]:
"""Record the fact that we're processing the file's results."""
self.formatter.beginning(filename)
yield self
@ -405,7 +401,7 @@ class StyleGuide:
line_number: int,
column_number: int,
text: str,
physical_line: Optional[str] = None,
physical_line: str | None = None,
) -> int:
"""Handle an error reported by a check.
@ -451,7 +447,7 @@ class StyleGuide:
return 1
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.
This provides information to the StyleGuide so that only the errors

View file

@ -1,4 +1,6 @@
"""Utility methods for flake8."""
from __future__ import annotations
import collections
import fnmatch as _fnmatch
import functools
@ -10,15 +12,9 @@ import re
import sys
import textwrap
import tokenize
from typing import Dict
from typing import List
from typing import NamedTuple
from typing import Optional
from typing import Pattern
from typing import Sequence
from typing import Set
from typing import Tuple
from typing import Union
from flake8 import exceptions
@ -30,7 +26,7 @@ NORMALIZE_PACKAGE_NAME_RE = re.compile(r"[-_.]+")
def parse_comma_separated_list(
value: str, regexp: Pattern[str] = COMMA_SEPARATED_LIST_RE
) -> List[str]:
) -> list[str]:
"""Parse a comma-separated list.
: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 = []
i = 0
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
value_: Union[Sequence[str], str]
) -> List[Tuple[str, List[str]]]:
value_: Sequence[str] | str,
) -> list[tuple[str, list[str]]]:
"""Parse a files-to-codes mapping.
A files-to-codes mapping a sequence of values specified as
@ -97,15 +93,15 @@ def parse_files_to_codes_mapping( # noqa: C901
else:
value = value_
ret: List[Tuple[str, List[str]]] = []
ret: list[tuple[str, list[str]]] = []
if not value.strip():
return ret
class State:
seen_sep = True
seen_colon = False
filenames: List[str] = []
codes: List[str] = []
filenames: list[str] = []
codes: list[str] = []
def _reset() -> None:
if State.codes:
@ -157,7 +153,7 @@ def parse_files_to_codes_mapping( # noqa: C901
def normalize_paths(
paths: Sequence[str], parent: str = os.curdir
) -> List[str]:
) -> list[str]:
"""Normalize a list of paths relative to a parent directory.
:returns:
@ -201,12 +197,12 @@ def stdin_get_value() -> str:
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 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.
:returns:
@ -218,7 +214,7 @@ def parse_unified_diff(diff: Optional[str] = None) -> Dict[str, Set[int]]:
number_of_rows = 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():
if number_of_rows:
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
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.
:param paths:

View file

@ -1,12 +1,11 @@
"""Contains the Violation error class used internally."""
from __future__ import annotations
import functools
import linecache
import logging
from typing import Dict
from typing import Match
from typing import NamedTuple
from typing import Optional
from typing import Set
from flake8 import defaults
from flake8 import utils
@ -16,7 +15,7 @@ LOG = logging.getLogger(__name__)
@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)
@ -28,7 +27,7 @@ class Violation(NamedTuple):
line_number: int
column_number: int
text: str
physical_line: Optional[str]
physical_line: str | None
def is_inline_ignored(self, disable_noqa: bool) -> bool:
"""Determine if a comment has been added to ignore this line.
@ -69,7 +68,7 @@ class Violation(NamedTuple):
)
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.
This function relies on the parsed data added via

View file

@ -1 +1,2 @@
"""This is here because mypy doesn't understand PEP 420."""
from __future__ import annotations

View file

@ -1,4 +1,6 @@
"""Test configuration for py.test."""
from __future__ import annotations
import sys
import flake8

View file

@ -1,4 +1,5 @@
"""Module that is off sys.path by default, for testing local-plugin-paths."""
from __future__ import annotations
class ExtensionTestPlugin2:

View file

@ -1,4 +1,6 @@
"""Test aggregation of config files and command-line options."""
from __future__ import annotations
import os
import pytest

View file

@ -1,4 +1,6 @@
"""Integration tests for the legacy api."""
from __future__ import annotations
from flake8.api import legacy

View file

@ -1,4 +1,6 @@
"""Integration tests for the checker submodule."""
from __future__ import annotations
import sys
from unittest import mock

View file

@ -1,4 +1,6 @@
"""Integration tests for the main entrypoint of flake8."""
from __future__ import annotations
import json
import os
import sys

View file

@ -1,4 +1,6 @@
"""Integration tests for plugin loading."""
from __future__ import annotations
import pytest
from flake8.main.cli import main

View file

@ -1,4 +1,6 @@
"""Shared fixtures between unit tests."""
from __future__ import annotations
import argparse
import pytest

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import configparser
import sys
from unittest import mock

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import importlib.machinery
import importlib.util
import os.path

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import argparse
import pytest

View file

@ -1,4 +1,6 @@
"""Tests for the Application class."""
from __future__ import annotations
import argparse
import pytest

View file

@ -1,4 +1,6 @@
"""Tests for the BaseFormatter object."""
from __future__ import annotations
import argparse
import sys
from unittest import mock

View file

@ -1,4 +1,6 @@
"""Tests for the Manager object for FileCheckers."""
from __future__ import annotations
import errno
import multiprocessing
from unittest import mock

View file

@ -1,3 +1,5 @@
from __future__ import annotations
from unittest import mock
from flake8._compat import importlib_metadata

View file

@ -1,4 +1,6 @@
"""Tests for the flake8.style_guide.DecisionEngine class."""
from __future__ import annotations
import argparse
import pytest

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import pytest

View file

@ -1,4 +1,6 @@
"""Tests for the flake8.exceptions module."""
from __future__ import annotations
import pickle
import pytest

View file

@ -1,4 +1,6 @@
"""Unit tests for the FileChecker class."""
from __future__ import annotations
import argparse
from unittest import mock

View file

@ -1,4 +1,6 @@
"""Tests for the FileProcessor class."""
from __future__ import annotations
import ast
import tokenize
from unittest import mock

View file

@ -1,4 +1,6 @@
"""Tests for the FilenameOnly formatter object."""
from __future__ import annotations
import argparse
from flake8.formatting import default

View file

@ -1,4 +1,6 @@
"""Tests for Flake8's legacy API."""
from __future__ import annotations
import argparse
import configparser
import os.path

View file

@ -1,3 +1,5 @@
from __future__ import annotations
from flake8.main import options

View file

@ -1,4 +1,6 @@
"""Tests for the Nothing formatter obbject."""
from __future__ import annotations
import argparse
from flake8.formatting import default

View file

@ -1,4 +1,6 @@
"""Unit tests for flake8.options.manager.Option."""
from __future__ import annotations
import functools
from unittest import mock

View file

@ -1,4 +1,6 @@
"""Unit tests for flake.options.manager.OptionManager."""
from __future__ import annotations
import argparse
import os
from unittest import mock

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import configparser
import os.path
from unittest import mock

View file

@ -1,4 +1,6 @@
"""Tests of pyflakes monkey patches."""
from __future__ import annotations
import ast
import pyflakes

View file

@ -1,4 +1,6 @@
"""Tests for the statistics module in Flake8."""
from __future__ import annotations
import pytest
from flake8 import statistics as stats

View file

@ -1,4 +1,6 @@
"""Tests for the flake8.style_guide.StyleGuide class."""
from __future__ import annotations
import argparse
from unittest import mock

View file

@ -1,4 +1,6 @@
"""Tests for flake8's utils module."""
from __future__ import annotations
import io
import logging
import os

View file

@ -1,4 +1,6 @@
"""Tests for the flake8.violation.Violation class."""
from __future__ import annotations
from unittest import mock
import pytest

View file

@ -1,6 +1,6 @@
[tox]
minversion=2.3.1
envlist = py36,py37,py38,flake8,linters,docs
envlist = py37,py38,flake8,linters,docs
[testenv]
deps =