flake8 7.2.0__tar.gz → 7.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. {flake8-7.2.0/src/flake8.egg-info → flake8-7.4.0}/PKG-INFO +4 -5
  2. {flake8-7.2.0 → flake8-7.4.0}/setup.cfg +3 -4
  3. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/__init__.py +2 -2
  4. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/_compat.py +7 -0
  5. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/api/legacy.py +2 -2
  6. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/checker.py +21 -56
  7. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/discover_files.py +1 -1
  8. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/formatting/base.py +1 -1
  9. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/main/application.py +1 -1
  10. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/main/debug.py +1 -1
  11. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/main/options.py +1 -1
  12. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/options/config.py +3 -3
  13. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/options/manager.py +2 -2
  14. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/plugins/finder.py +5 -5
  15. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/plugins/pyflakes.py +5 -1
  16. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/processor.py +19 -8
  17. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/statistics.py +2 -2
  18. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/style_guide.py +5 -5
  19. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/utils.py +3 -3
  20. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/violation.py +1 -1
  21. {flake8-7.2.0 → flake8-7.4.0/src/flake8.egg-info}/PKG-INFO +4 -5
  22. flake8-7.4.0/src/flake8.egg-info/requires.txt +3 -0
  23. flake8-7.2.0/src/flake8.egg-info/requires.txt +0 -3
  24. {flake8-7.2.0 → flake8-7.4.0}/LICENSE +0 -0
  25. {flake8-7.2.0 → flake8-7.4.0}/README.rst +0 -0
  26. {flake8-7.2.0 → flake8-7.4.0}/setup.py +0 -0
  27. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/__main__.py +0 -0
  28. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/api/__init__.py +0 -0
  29. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/defaults.py +0 -0
  30. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/exceptions.py +0 -0
  31. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/formatting/__init__.py +0 -0
  32. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/formatting/_windows_color.py +0 -0
  33. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/formatting/default.py +0 -0
  34. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/main/__init__.py +0 -0
  35. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/main/cli.py +0 -0
  36. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/options/__init__.py +0 -0
  37. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/options/aggregator.py +0 -0
  38. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/options/parse_args.py +0 -0
  39. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/plugins/__init__.py +0 -0
  40. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/plugins/pycodestyle.py +0 -0
  41. {flake8-7.2.0 → flake8-7.4.0}/src/flake8/plugins/reporter.py +0 -0
  42. {flake8-7.2.0 → flake8-7.4.0}/src/flake8.egg-info/SOURCES.txt +0 -0
  43. {flake8-7.2.0 → flake8-7.4.0}/src/flake8.egg-info/dependency_links.txt +0 -0
  44. {flake8-7.2.0 → flake8-7.4.0}/src/flake8.egg-info/entry_points.txt +0 -0
  45. {flake8-7.2.0 → flake8-7.4.0}/src/flake8.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flake8
3
- Version: 7.2.0
3
+ Version: 7.4.0
4
4
  Summary: the modular source code checker: pep8 pyflakes and co
5
5
  Home-page: https://github.com/pycqa/flake8
6
6
  Author: Tarek Ziade
@@ -12,7 +12,6 @@ Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Environment :: Console
13
13
  Classifier: Framework :: Flake8
14
14
  Classifier: Intended Audience :: Developers
15
- Classifier: License :: OSI Approved :: MIT License
16
15
  Classifier: Programming Language :: Python
17
16
  Classifier: Programming Language :: Python :: 3
18
17
  Classifier: Programming Language :: Python :: 3 :: Only
@@ -20,12 +19,12 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
20
19
  Classifier: Programming Language :: Python :: Implementation :: PyPy
21
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
21
  Classifier: Topic :: Software Development :: Quality Assurance
23
- Requires-Python: >=3.9
22
+ Requires-Python: >=3.10
24
23
  Description-Content-Type: text/x-rst
25
24
  License-File: LICENSE
26
25
  Requires-Dist: mccabe<0.8.0,>=0.7.0
27
- Requires-Dist: pycodestyle<2.14.0,>=2.13.0
28
- Requires-Dist: pyflakes<3.4.0,>=3.3.0
26
+ Requires-Dist: pycodestyle<2.16.0,>=2.15.0
27
+ Requires-Dist: pyflakes<4.1.0,>=4.0.0
29
28
 
30
29
  .. image:: https://github.com/PyCQA/flake8/workflows/main/badge.svg
31
30
  :target: https://github.com/PyCQA/flake8/actions?query=workflow%3Amain
@@ -16,7 +16,6 @@ classifiers =
16
16
  Environment :: Console
17
17
  Framework :: Flake8
18
18
  Intended Audience :: Developers
19
- License :: OSI Approved :: MIT License
20
19
  Programming Language :: Python
21
20
  Programming Language :: Python :: 3
22
21
  Programming Language :: Python :: 3 :: Only
@@ -29,9 +28,9 @@ classifiers =
29
28
  packages = find:
30
29
  install_requires =
31
30
  mccabe>=0.7.0,<0.8.0
32
- pycodestyle>=2.13.0,<2.14.0
33
- pyflakes>=3.3.0,<3.4.0
34
- python_requires = >=3.9
31
+ pycodestyle>=2.15.0,<2.16.0
32
+ pyflakes>=4.0.0,<4.1.0
33
+ python_requires = >=3.10
35
34
  package_dir =
36
35
  =src
37
36
 
@@ -17,7 +17,7 @@ import sys
17
17
  LOG = logging.getLogger(__name__)
18
18
  LOG.addHandler(logging.NullHandler())
19
19
 
20
- __version__ = "7.2.0"
20
+ __version__ = "7.4.0"
21
21
  __version_info__ = tuple(int(i) for i in __version__.split(".") if i.isdigit())
22
22
 
23
23
  _VERBOSITY_TO_LOG_LEVEL = {
@@ -66,5 +66,5 @@ def configure_logging(
66
66
  LOG.addHandler(handler)
67
67
  LOG.setLevel(log_level)
68
68
  LOG.debug(
69
- "Added a %s logging handler to logger root at %s", filename, __name__
69
+ "Added a %s logging handler to logger root at %s", filename, __name__,
70
70
  )
@@ -9,3 +9,10 @@ if sys.version_info >= (3, 12): # pragma: >=3.12 cover
9
9
  FSTRING_END = tokenize.FSTRING_END
10
10
  else: # pragma: <3.12 cover
11
11
  FSTRING_START = FSTRING_MIDDLE = FSTRING_END = -1
12
+
13
+ if sys.version_info >= (3, 14): # pragma: >=3.14 cover
14
+ TSTRING_START = tokenize.TSTRING_START
15
+ TSTRING_MIDDLE = tokenize.TSTRING_MIDDLE
16
+ TSTRING_END = tokenize.TSTRING_END
17
+ else: # pragma: <3.14 cover
18
+ TSTRING_START = TSTRING_MIDDLE = TSTRING_END = -1
@@ -135,7 +135,7 @@ class StyleGuide:
135
135
  stdin_display_name=self.options.stdin_display_name,
136
136
  filename_patterns=self.options.filename,
137
137
  exclude=self.options.exclude,
138
- )
138
+ ),
139
139
  )
140
140
  return not paths
141
141
 
@@ -153,7 +153,7 @@ class StyleGuide:
153
153
  if not issubclass(reporter, formatter.BaseFormatter):
154
154
  raise ValueError(
155
155
  "Report should be subclass of "
156
- "flake8.formatter.BaseFormatter."
156
+ "flake8.formatter.BaseFormatter.",
157
157
  )
158
158
  self._application.formatter = reporter(self.options)
159
159
  self._application.guide = None
@@ -19,6 +19,7 @@ from flake8 import exceptions
19
19
  from flake8 import processor
20
20
  from flake8 import utils
21
21
  from flake8._compat import FSTRING_START
22
+ from flake8._compat import TSTRING_START
22
23
  from flake8.discover_files import expand_paths
23
24
  from flake8.options.parse_args import parse_args
24
25
  from flake8.plugins.finder import Checkers
@@ -44,40 +45,39 @@ SERIAL_RETRY_ERRNOS = {
44
45
  # noise in diffs.
45
46
  }
46
47
 
47
- _mp_plugins: Checkers
48
- _mp_options: argparse.Namespace
48
+ _mp: tuple[Checkers, argparse.Namespace] | None = None
49
49
 
50
50
 
51
51
  @contextlib.contextmanager
52
52
  def _mp_prefork(
53
- plugins: Checkers, options: argparse.Namespace
53
+ plugins: Checkers, options: argparse.Namespace,
54
54
  ) -> Generator[None]:
55
55
  # we can save significant startup work w/ `fork` multiprocessing
56
- global _mp_plugins, _mp_options
57
- _mp_plugins, _mp_options = plugins, options
56
+ global _mp
57
+ _mp = plugins, options
58
58
  try:
59
59
  yield
60
60
  finally:
61
- del _mp_plugins, _mp_options
61
+ _mp = None
62
62
 
63
63
 
64
64
  def _mp_init(argv: Sequence[str]) -> None:
65
- global _mp_plugins, _mp_options
65
+ global _mp
66
66
 
67
67
  # Ensure correct signaling of ^C using multiprocessing.Pool.
68
68
  signal.signal(signal.SIGINT, signal.SIG_IGN)
69
69
 
70
- try:
71
- # for `fork` this'll already be set
72
- _mp_plugins, _mp_options # noqa: B018
73
- except NameError:
70
+ # for `fork` this'll already be set
71
+ if _mp is None:
74
72
  plugins, options = parse_args(argv)
75
- _mp_plugins, _mp_options = plugins.checkers, options
73
+ _mp = plugins.checkers, options
76
74
 
77
75
 
78
76
  def _mp_run(filename: str) -> tuple[str, Results, dict[str, int]]:
77
+ assert _mp is not None, _mp
78
+ plugins, options = _mp
79
79
  return FileChecker(
80
- filename=filename, plugins=_mp_plugins, options=_mp_options
80
+ filename=filename, plugins=plugins, options=options,
81
81
  ).run_checks()
82
82
 
83
83
 
@@ -137,7 +137,7 @@ class Manager:
137
137
  if utils.is_using_stdin(self.options.filenames):
138
138
  LOG.warning(
139
139
  "The --jobs option is not compatible with supplying "
140
- "input using - . Ignoring --jobs arguments."
140
+ "input using - . Ignoring --jobs arguments.",
141
141
  )
142
142
  return 0
143
143
 
@@ -252,7 +252,7 @@ class Manager:
252
252
  stdin_display_name=self.options.stdin_display_name,
253
253
  filename_patterns=self.options.filename,
254
254
  exclude=self.exclude,
255
- )
255
+ ),
256
256
  )
257
257
  self.jobs = min(len(self.filenames), self.jobs)
258
258
 
@@ -332,11 +332,11 @@ class FileChecker:
332
332
  assert self.processor is not None, self.filename
333
333
  try:
334
334
  params = self.processor.keyword_arguments_for(
335
- plugin.parameters, arguments
335
+ plugin.parameters, arguments,
336
336
  )
337
337
  except AttributeError as ae:
338
338
  raise exceptions.PluginRequestedUnknownParameters(
339
- plugin_name=plugin.display_name, exception=ae
339
+ plugin_name=plugin.display_name, exception=ae,
340
340
  )
341
341
  try:
342
342
  return plugin.obj(**arguments, **params)
@@ -372,43 +372,6 @@ class FileChecker:
372
372
  token = ()
373
373
  row, column = (1, 0)
374
374
 
375
- if (
376
- column > 0
377
- and token
378
- and isinstance(exception, SyntaxError)
379
- and len(token) == 4 # Python 3.9 or earlier
380
- ):
381
- # NOTE(sigmavirus24): SyntaxErrors report 1-indexed column
382
- # numbers. We need to decrement the column number by 1 at
383
- # least.
384
- column_offset = 1
385
- row_offset = 0
386
- # See also: https://github.com/pycqa/flake8/issues/169,
387
- # https://github.com/PyCQA/flake8/issues/1372
388
- # On Python 3.9 and earlier, token will be a 4-item tuple with the
389
- # last item being the string. Starting with 3.10, they added to
390
- # the tuple so now instead of it ending with the code that failed
391
- # to parse, it ends with the end of the section of code that
392
- # failed to parse. Luckily the absolute position in the tuple is
393
- # stable across versions so we can use that here
394
- physical_line = token[3]
395
-
396
- # NOTE(sigmavirus24): Not all "tokens" have a string as the last
397
- # argument. In this event, let's skip trying to find the correct
398
- # column and row values.
399
- if physical_line is not None:
400
- # NOTE(sigmavirus24): SyntaxErrors also don't exactly have a
401
- # "physical" line so much as what was accumulated by the point
402
- # tokenizing failed.
403
- # See also: https://github.com/pycqa/flake8/issues/169
404
- lines = physical_line.rstrip("\n").split("\n")
405
- row_offset = len(lines) - 1
406
- logical_line = lines[0]
407
- logical_line_length = len(logical_line)
408
- if column > logical_line_length:
409
- column = logical_line_length
410
- row -= row_offset
411
- column -= column_offset
412
375
  return row, column
413
376
 
414
377
  def run_ast_checks(self) -> None:
@@ -548,12 +511,14 @@ class FileChecker:
548
511
  self.run_logical_checks()
549
512
 
550
513
  def check_physical_eol(
551
- self, token: tokenize.TokenInfo, prev_physical: str
514
+ self, token: tokenize.TokenInfo, prev_physical: str,
552
515
  ) -> None:
553
516
  """Run physical checks if and only if it is at the end of the line."""
554
517
  assert self.processor is not None
555
518
  if token.type == FSTRING_START: # pragma: >=3.12 cover
556
519
  self.processor.fstring_start(token.start[0])
520
+ elif token.type == TSTRING_START: # pragma: >=3.14 cover
521
+ self.processor.tstring_start(token.start[0])
557
522
  # a newline token ends a single physical line.
558
523
  elif processor.is_eol_token(token):
559
524
  # if the file does not end with a newline, the NEWLINE
@@ -596,7 +561,7 @@ def _try_initialize_processpool(
596
561
 
597
562
 
598
563
  def find_offset(
599
- offset: int, mapping: processor._LogicalMapping
564
+ offset: int, mapping: processor._LogicalMapping,
600
565
  ) -> tuple[int, int]:
601
566
  """Find the offset tuple for a single offset."""
602
567
  if isinstance(offset, tuple):
@@ -3,9 +3,9 @@ from __future__ import annotations
3
3
 
4
4
  import logging
5
5
  import os.path
6
+ from collections.abc import Callable
6
7
  from collections.abc import Generator
7
8
  from collections.abc import Sequence
8
- from typing import Callable
9
9
 
10
10
  from flake8 import utils
11
11
 
@@ -110,7 +110,7 @@ class BaseFormatter:
110
110
  The formatted error string.
111
111
  """
112
112
  raise NotImplementedError(
113
- "Subclass of BaseFormatter did not implement" " format."
113
+ "Subclass of BaseFormatter did not implement" " format.",
114
114
  )
115
115
 
116
116
  def show_statistics(self, statistics: Statistics) -> None:
@@ -76,7 +76,7 @@ class Application:
76
76
  assert self.formatter is not None
77
77
  assert self.options is not None
78
78
  self.guide = style_guide.StyleGuideManager(
79
- self.options, self.formatter
79
+ self.options, self.formatter,
80
80
  )
81
81
 
82
82
  def make_file_checker_manager(self, argv: Sequence[str]) -> None:
@@ -14,7 +14,7 @@ def information(version: str, plugins: Plugins) -> dict[str, Any]:
14
14
  (loaded.plugin.package, loaded.plugin.version)
15
15
  for loaded in plugins.all_plugins()
16
16
  if loaded.plugin.package not in {"flake8", "local"}
17
- }
17
+ },
18
18
  )
19
19
  return {
20
20
  "version": version,
@@ -32,7 +32,7 @@ def stage1_arg_parser() -> argparse.ArgumentParser:
32
32
  )
33
33
 
34
34
  parser.add_argument(
35
- "--output-file", default=None, help="Redirect report to a file."
35
+ "--output-file", default=None, help="Redirect report to a file.",
36
36
  )
37
37
 
38
38
  # Config file options
@@ -78,7 +78,7 @@ def load_config(
78
78
  if config is not None:
79
79
  if not cfg.read(config, encoding="UTF-8"):
80
80
  raise exceptions.ExecutionError(
81
- f"The specified config file does not exist: {config}"
81
+ f"The specified config file does not exist: {config}",
82
82
  )
83
83
  cfg_dir = os.path.dirname(config)
84
84
  else:
@@ -89,7 +89,7 @@ def load_config(
89
89
  for filename in extra:
90
90
  if not cfg.read(filename, encoding="UTF-8"):
91
91
  raise exceptions.ExecutionError(
92
- f"The specified config file does not exist: {filename}"
92
+ f"The specified config file does not exist: {filename}",
93
93
  )
94
94
 
95
95
  return cfg, cfg_dir
@@ -131,7 +131,7 @@ def parse_config(
131
131
  raise ValueError(
132
132
  f"Error code {error_code!r} "
133
133
  f"supplied to {option_name!r} option "
134
- f"does not match {VALID_CODE_PREFIX.pattern!r}"
134
+ f"does not match {VALID_CODE_PREFIX.pattern!r}",
135
135
  )
136
136
 
137
137
  assert option.config_name is not None
@@ -5,9 +5,9 @@ import argparse
5
5
  import enum
6
6
  import functools
7
7
  import logging
8
+ from collections.abc import Callable
8
9
  from collections.abc import Sequence
9
10
  from typing import Any
10
- from typing import Callable
11
11
 
12
12
  from flake8 import utils
13
13
  from flake8.plugins.finder import Plugins
@@ -165,7 +165,7 @@ class Option:
165
165
  if long_option_name is _ARG.NO:
166
166
  raise ValueError(
167
167
  "When specifying parse_from_config=True, "
168
- "a long_option_name must also be specified."
168
+ "a long_option_name must also be specified.",
169
169
  )
170
170
  self.config_name = long_option_name[2:].replace("-", "_")
171
171
 
@@ -83,8 +83,8 @@ class Plugins(NamedTuple):
83
83
  f"{loaded.plugin.package}: {loaded.plugin.version}"
84
84
  for loaded in self.all_plugins()
85
85
  if loaded.plugin.package not in {"flake8", "local"}
86
- }
87
- )
86
+ },
87
+ ),
88
88
  )
89
89
 
90
90
 
@@ -167,7 +167,7 @@ def _flake8_plugins(
167
167
  # ideally pycodestyle's plugin entrypoints would exactly represent
168
168
  # the codes they produce...
169
169
  yield Plugin(
170
- pycodestyle_meta["name"], pycodestyle_meta["version"], ep
170
+ pycodestyle_meta["name"], pycodestyle_meta["version"], ep,
171
171
  )
172
172
  else:
173
173
  yield Plugin(name, version, ep)
@@ -240,7 +240,7 @@ def _check_required_plugins(
240
240
  f"required plugins were not installed!\n"
241
241
  f"- installed: {', '.join(sorted(plugin_names))}\n"
242
242
  f"- expected: {', '.join(sorted(expected_names))}\n"
243
- f"- missing: {', '.join(sorted(missing_plugins))}"
243
+ f"- missing: {', '.join(sorted(missing_plugins))}",
244
244
  )
245
245
 
246
246
 
@@ -338,7 +338,7 @@ def _classify_plugins(
338
338
  if not VALID_CODE_PREFIX.match(loaded.entry_name):
339
339
  raise ExecutionError(
340
340
  f"plugin code for `{loaded.display_name}` does not match "
341
- f"{VALID_CODE_PREFIX.pattern}"
341
+ f"{VALID_CODE_PREFIX.pattern}",
342
342
  )
343
343
 
344
344
  return Plugins(
@@ -36,6 +36,7 @@ FLAKE8_PYFLAKES_CODES = {
36
36
  "StringDotFormatMissingArgument": "F524",
37
37
  "StringDotFormatMixingAutomatic": "F525",
38
38
  "FStringMissingPlaceholders": "F541",
39
+ "TStringMissingPlaceholders": "F542",
39
40
  "MultiValueRepeatedKeyLiteral": "F601",
40
41
  "MultiValueRepeatedKeyVariable": "F602",
41
42
  "TooManyExpressionsInStarredAssignment": "F621",
@@ -49,6 +50,8 @@ FLAKE8_PYFLAKES_CODES = {
49
50
  "YieldOutsideFunction": "F704",
50
51
  "ReturnOutsideFunction": "F706",
51
52
  "DefaultExceptNotLast": "F707",
53
+ "LazyImportNotAtModuleScope": "F708",
54
+ "LazyImportStarNotPermitted": "F709",
52
55
  "DoctestSyntaxError": "F721",
53
56
  "ForwardAnnotationSyntaxError": "F722",
54
57
  "RedefinedWhileUnused": "F811",
@@ -59,6 +62,7 @@ FLAKE8_PYFLAKES_CODES = {
59
62
  "DuplicateArgument": "F831",
60
63
  "UnusedVariable": "F841",
61
64
  "UnusedAnnotation": "F842",
65
+ "EagerUseOfLazyImport": "F851",
62
66
  "RaiseNotImplemented": "F901",
63
67
  }
64
68
 
@@ -71,7 +75,7 @@ class FlakesChecker(pyflakes.checker.Checker):
71
75
  def __init__(self, tree: ast.AST, filename: str) -> None:
72
76
  """Initialize the PyFlakes plugin with an AST tree and filename."""
73
77
  super().__init__(
74
- tree, filename=filename, withDoctest=self.with_doctest
78
+ tree, filename=filename, withDoctest=self.with_doctest,
75
79
  )
76
80
 
77
81
  @classmethod
@@ -13,13 +13,15 @@ from flake8 import defaults
13
13
  from flake8 import utils
14
14
  from flake8._compat import FSTRING_END
15
15
  from flake8._compat import FSTRING_MIDDLE
16
+ from flake8._compat import TSTRING_END
17
+ from flake8._compat import TSTRING_MIDDLE
16
18
  from flake8.plugins.finder import LoadedPlugin
17
19
 
18
20
  LOG = logging.getLogger(__name__)
19
21
  NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE])
20
22
 
21
23
  SKIP_TOKENS = frozenset(
22
- [tokenize.NL, tokenize.NEWLINE, tokenize.INDENT, tokenize.DEDENT]
24
+ [tokenize.NL, tokenize.NEWLINE, tokenize.INDENT, tokenize.DEDENT],
23
25
  )
24
26
 
25
27
  _LogicalMapping = list[tuple[int, tuple[int, int]]]
@@ -113,7 +115,7 @@ class FileProcessor:
113
115
  self.verbose = options.verbose
114
116
  #: Statistics dictionary
115
117
  self.statistics = {"logical lines": 0}
116
- self._fstring_start = -1
118
+ self._fstring_start = self._tstring_start = -1
117
119
 
118
120
  @functools.cached_property
119
121
  def file_tokens(self) -> list[tokenize.TokenInfo]:
@@ -125,10 +127,16 @@ class FileProcessor:
125
127
  """Signal the beginning of an fstring."""
126
128
  self._fstring_start = lineno
127
129
 
130
+ def tstring_start(self, lineno: int) -> None: # pragma: >=3.14 cover
131
+ """Signal the beginning of an tstring."""
132
+ self._tstring_start = lineno
133
+
128
134
  def multiline_string(self, token: tokenize.TokenInfo) -> Generator[str]:
129
135
  """Iterate through the lines of a multiline string."""
130
136
  if token.type == FSTRING_END: # pragma: >=3.12 cover
131
137
  start = self._fstring_start
138
+ elif token.type == TSTRING_END: # pragma: >=3.14 cover
139
+ start = self._tstring_start
132
140
  else:
133
141
  start = token.start[0]
134
142
 
@@ -165,7 +173,7 @@ class FileProcessor:
165
173
  """Update the checker_state attribute for the plugin."""
166
174
  if "checker_state" in plugin.parameters:
167
175
  self.checker_state = self._checker_states.setdefault(
168
- plugin.entry_name, {}
176
+ plugin.entry_name, {},
169
177
  )
170
178
 
171
179
  def next_logical_line(self) -> None:
@@ -198,7 +206,10 @@ class FileProcessor:
198
206
  continue
199
207
  if token_type == tokenize.STRING:
200
208
  text = mutate_string(text)
201
- elif token_type == FSTRING_MIDDLE: # pragma: >=3.12 cover
209
+ elif token_type in {
210
+ FSTRING_MIDDLE,
211
+ TSTRING_MIDDLE,
212
+ }: # pragma: >=3.12 cover # noqa: E501
202
213
  # A curly brace in an FSTRING_MIDDLE token must be an escaped
203
214
  # curly brace. Both 'text' and 'end' will account for the
204
215
  # escaped version of the token (i.e. a single brace) rather
@@ -269,7 +280,7 @@ class FileProcessor:
269
280
 
270
281
  def _noqa_line_range(self, min_line: int, max_line: int) -> dict[int, str]:
271
282
  line_range = range(min_line, max_line + 1)
272
- joined = "".join(self.lines[min_line - 1 : max_line])
283
+ joined = "".join(self.lines[min_line - 1: max_line])
273
284
  return dict.fromkeys(line_range, joined)
274
285
 
275
286
  @functools.cached_property
@@ -356,7 +367,7 @@ class FileProcessor:
356
367
  elif any(defaults.NOQA_FILE.search(line) for line in self.lines):
357
368
  LOG.warning(
358
369
  "Detected `flake8: noqa` on line with code. To ignore an "
359
- "error on a line use `noqa` instead."
370
+ "error on a line use `noqa` instead.",
360
371
  )
361
372
  return False
362
373
  else:
@@ -377,12 +388,12 @@ class FileProcessor:
377
388
 
378
389
  def is_eol_token(token: tokenize.TokenInfo) -> bool:
379
390
  """Check if the token is an end-of-line token."""
380
- return token[0] in NEWLINE or token[4][token[3][1] :].lstrip() == "\\\n"
391
+ return token[0] in NEWLINE or token[4][token[3][1]:].lstrip() == "\\\n"
381
392
 
382
393
 
383
394
  def is_multiline_string(token: tokenize.TokenInfo) -> bool:
384
395
  """Check if this is a multiline string."""
385
- return token.type == FSTRING_END or (
396
+ return token.type in {FSTRING_END, TSTRING_END} or (
386
397
  token.type == tokenize.STRING and "\n" in token.string
387
398
  )
388
399
 
@@ -35,7 +35,7 @@ class Statistics:
35
35
  self._store[key].increment()
36
36
 
37
37
  def statistics_for(
38
- self, prefix: str, filename: str | None = None
38
+ self, prefix: str, filename: str | None = None,
39
39
  ) -> Generator[Statistic]:
40
40
  """Generate statistics for the prefix and filename.
41
41
 
@@ -108,7 +108,7 @@ class Statistic:
108
108
  """
109
109
 
110
110
  def __init__(
111
- self, error_code: str, filename: str, message: str, count: int
111
+ self, error_code: str, filename: str, message: str, count: int,
112
112
  ) -> None:
113
113
  """Initialize our Statistic."""
114
114
  self.error_code = error_code
@@ -218,7 +218,7 @@ class StyleGuideManager:
218
218
  self.decider = decider or DecisionEngine(options)
219
219
  self.style_guides: list[StyleGuide] = []
220
220
  self.default_style_guide = StyleGuide(
221
- options, formatter, self.stats, decider=decider
221
+ options, formatter, self.stats, decider=decider,
222
222
  )
223
223
  self.style_guides = [
224
224
  self.default_style_guide,
@@ -228,7 +228,7 @@ class StyleGuideManager:
228
228
  self.style_guide_for = functools.cache(self._style_guide_for)
229
229
 
230
230
  def populate_style_guides_with(
231
- self, options: argparse.Namespace
231
+ self, options: argparse.Namespace,
232
232
  ) -> Generator[StyleGuide]:
233
233
  """Generate style guides from the per-file-ignores option.
234
234
 
@@ -240,7 +240,7 @@ class StyleGuideManager:
240
240
  per_file = utils.parse_files_to_codes_mapping(options.per_file_ignores)
241
241
  for filename, violations in per_file:
242
242
  yield self.default_style_guide.copy(
243
- filename=filename, extend_ignore_with=violations
243
+ filename=filename, extend_ignore_with=violations,
244
244
  )
245
245
 
246
246
  def _style_guide_for(self, filename: str) -> StyleGuide:
@@ -288,7 +288,7 @@ class StyleGuideManager:
288
288
  """
289
289
  guide = self.style_guide_for(filename)
290
290
  return guide.handle_error(
291
- code, filename, line_number, column_number, text, physical_line
291
+ code, filename, line_number, column_number, text, physical_line,
292
292
  )
293
293
 
294
294
 
@@ -330,7 +330,7 @@ class StyleGuide:
330
330
  options.extend_ignore = options.extend_ignore or []
331
331
  options.extend_ignore.extend(extend_ignore_with or [])
332
332
  return StyleGuide(
333
- options, self.formatter, self.stats, filename=filename
333
+ options, self.formatter, self.stats, filename=filename,
334
334
  )
335
335
 
336
336
  @contextlib.contextmanager
@@ -23,7 +23,7 @@ NORMALIZE_PACKAGE_NAME_RE = re.compile(r"[-_.]+")
23
23
 
24
24
 
25
25
  def parse_comma_separated_list(
26
- value: str, regexp: Pattern[str] = COMMA_SEPARATED_LIST_RE
26
+ value: str, regexp: Pattern[str] = COMMA_SEPARATED_LIST_RE,
27
27
  ) -> list[str]:
28
28
  """Parse a comma-separated list.
29
29
 
@@ -115,7 +115,7 @@ def parse_files_to_codes_mapping( # noqa: C901
115
115
  f"Expected `per-file-ignores` to be a mapping from file exclude "
116
116
  f"patterns to ignore codes.\n\n"
117
117
  f"Configured `per-file-ignores` setting:\n\n"
118
- f"{textwrap.indent(value.strip(), ' ')}"
118
+ f"{textwrap.indent(value.strip(), ' ')}",
119
119
  )
120
120
 
121
121
  for token in _tokenize_files_to_codes_mapping(value):
@@ -150,7 +150,7 @@ def parse_files_to_codes_mapping( # noqa: C901
150
150
 
151
151
 
152
152
  def normalize_paths(
153
- paths: Sequence[str], parent: str = os.curdir
153
+ paths: Sequence[str], parent: str = os.curdir,
154
154
  ) -> list[str]:
155
155
  """Normalize a list of paths relative to a parent directory.
156
156
 
@@ -64,6 +64,6 @@ class Violation(NamedTuple):
64
64
  return True
65
65
 
66
66
  LOG.debug(
67
- "%r is not ignored inline with ``# noqa: %s``", self, codes_str
67
+ "%r is not ignored inline with ``# noqa: %s``", self, codes_str,
68
68
  )
69
69
  return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flake8
3
- Version: 7.2.0
3
+ Version: 7.4.0
4
4
  Summary: the modular source code checker: pep8 pyflakes and co
5
5
  Home-page: https://github.com/pycqa/flake8
6
6
  Author: Tarek Ziade
@@ -12,7 +12,6 @@ Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Environment :: Console
13
13
  Classifier: Framework :: Flake8
14
14
  Classifier: Intended Audience :: Developers
15
- Classifier: License :: OSI Approved :: MIT License
16
15
  Classifier: Programming Language :: Python
17
16
  Classifier: Programming Language :: Python :: 3
18
17
  Classifier: Programming Language :: Python :: 3 :: Only
@@ -20,12 +19,12 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
20
19
  Classifier: Programming Language :: Python :: Implementation :: PyPy
21
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
21
  Classifier: Topic :: Software Development :: Quality Assurance
23
- Requires-Python: >=3.9
22
+ Requires-Python: >=3.10
24
23
  Description-Content-Type: text/x-rst
25
24
  License-File: LICENSE
26
25
  Requires-Dist: mccabe<0.8.0,>=0.7.0
27
- Requires-Dist: pycodestyle<2.14.0,>=2.13.0
28
- Requires-Dist: pyflakes<3.4.0,>=3.3.0
26
+ Requires-Dist: pycodestyle<2.16.0,>=2.15.0
27
+ Requires-Dist: pyflakes<4.1.0,>=4.0.0
29
28
 
30
29
  .. image:: https://github.com/PyCQA/flake8/workflows/main/badge.svg
31
30
  :target: https://github.com/PyCQA/flake8/actions?query=workflow%3Amain
@@ -0,0 +1,3 @@
1
+ mccabe<0.8.0,>=0.7.0
2
+ pycodestyle<2.16.0,>=2.15.0
3
+ pyflakes<4.1.0,>=4.0.0
@@ -1,3 +0,0 @@
1
- mccabe<0.8.0,>=0.7.0
2
- pycodestyle<2.14.0,>=2.13.0
3
- pyflakes<3.4.0,>=3.3.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes