Preserve legacy API options in workers

This commit is contained in:
Sean Doherty 2026-05-16 22:43:12 -05:00
parent ee03327c82
commit 4ae06799c3
6 changed files with 53 additions and 7 deletions

View file

@ -204,13 +204,15 @@ def get_style_guide(**kwargs: Any) -> StyleGuide:
# options set instead before we make our formatter, notifier, internal
# style guide and file checker manager.
options = application.options
option_overrides = {}
for key, value in kwargs.items():
try:
getattr(options, key)
setattr(options, key, value)
option_overrides[key] = value
except AttributeError:
LOG.error('Could not update option "%s"', key)
application.make_formatter()
application.make_guide()
application.make_file_checker_manager([])
application.make_file_checker_manager([], option_overrides)
return StyleGuide(application)

View file

@ -61,7 +61,10 @@ def _mp_prefork(
_mp = None
def _mp_init(argv: Sequence[str]) -> None:
def _mp_init(
argv: Sequence[str],
option_overrides: dict[str, Any] | None = None,
) -> None:
global _mp
# Ensure correct signaling of ^C using multiprocessing.Pool.
@ -70,6 +73,9 @@ def _mp_init(argv: Sequence[str]) -> None:
# for `fork` this'll already be set
if _mp is None:
plugins, options = parse_args(argv)
if option_overrides:
for key, value in option_overrides.items():
setattr(options, key, value)
_mp = plugins.checkers, options
@ -105,6 +111,7 @@ class Manager:
style_guide: StyleGuideManager,
plugins: Checkers,
argv: Sequence[str],
option_overrides: dict[str, Any] | None = None,
) -> None:
"""Initialize our Manager instance."""
self.style_guide = style_guide
@ -119,6 +126,7 @@ class Manager:
}
self.exclude = (*self.options.exclude, *self.options.extend_exclude)
self.argv = argv
self.option_overrides = option_overrides
self.results: list[tuple[str, Results, dict[str, int]]] = []
def _process_statistics(self) -> None:
@ -192,7 +200,9 @@ class Manager:
def run_parallel(self) -> None:
"""Run the checkers in parallel."""
with _mp_prefork(self.plugins, self.options):
pool = _try_initialize_processpool(self.jobs, self.argv)
pool = _try_initialize_processpool(
self.jobs, self.argv, self.option_overrides,
)
if pool is None:
self.run_serial()
@ -547,10 +557,13 @@ class FileChecker:
def _try_initialize_processpool(
job_count: int,
argv: Sequence[str],
option_overrides: dict[str, Any] | None = None,
) -> multiprocessing.pool.Pool | None:
"""Return a new process pool instance if we are able to create one."""
try:
return multiprocessing.Pool(job_count, _mp_init, initargs=(argv,))
return multiprocessing.Pool(
job_count, _mp_init, initargs=(argv, option_overrides),
)
except OSError as err:
if err.errno not in SERIAL_RETRY_ERRNOS:
raise

View file

@ -6,6 +6,7 @@ import json
import logging
import time
from collections.abc import Sequence
from typing import Any
import flake8
from flake8 import checker
@ -79,7 +80,11 @@ class Application:
self.options, self.formatter,
)
def make_file_checker_manager(self, argv: Sequence[str]) -> None:
def make_file_checker_manager(
self,
argv: Sequence[str],
option_overrides: dict[str, Any] | None = None,
) -> None:
"""Initialize our FileChecker Manager."""
assert self.guide is not None
assert self.plugins is not None
@ -87,6 +92,7 @@ class Application:
style_guide=self.guide,
plugins=self.plugins.checkers,
argv=argv,
option_overrides=option_overrides,
)
def run_checks(self) -> None:

View file

@ -13,3 +13,17 @@ def test_legacy_api(tmpdir):
style_guide = legacy.get_style_guide()
report = style_guide.check_files([t_py.strpath])
assert report.total_errors == 1
def test_legacy_api_parallel_checks_use_option_overrides(tmpdir):
long_line = f"x = \"{'a' * 80}\"\n"
assert len(long_line.rstrip()) == 86
file1 = tmpdir.join("file1.py")
file1.write(long_line)
file2 = tmpdir.join("file2.py")
file2.write(long_line)
style_guide = legacy.get_style_guide(max_line_length=88)
report = style_guide.check_files([file1.strpath, file2.strpath])
assert report.total_errors == 0

View file

@ -291,7 +291,7 @@ def test_acquire_when_multiprocessing_pool_can_initialize():
with mock.patch("multiprocessing.Pool") as pool:
result = checker._try_initialize_processpool(2, [])
pool.assert_called_once_with(2, checker._mp_init, initargs=([],))
pool.assert_called_once_with(2, checker._mp_init, initargs=([], None))
assert result is pool.return_value
@ -310,7 +310,7 @@ def test_acquire_when_multiprocessing_pool_can_not_initialize():
with mock.patch("multiprocessing.Pool", side_effect=ImportError) as pool:
result = checker._try_initialize_processpool(2, [])
pool.assert_called_once_with(2, checker._mp_init, initargs=([],))
pool.assert_called_once_with(2, checker._mp_init, initargs=([], None))
assert result is None

View file

@ -63,6 +63,17 @@ def test_multiprocessing_cpu_count_not_implemented():
assert manager.jobs == 0
def test_mp_init_applies_option_overrides():
checker._mp = None
try:
checker._mp_init([], {"max_line_length": 88})
assert checker._mp is not None
_, options = checker._mp
assert options.max_line_length == 88
finally:
checker._mp = None
def test_jobs_count_limited_to_file_count():
style_guide = style_guide_mock()
style_guide.options.jobs = JobsArgument("4")