Skip to content

Commit 2047a79

Browse files
committed
refactor: move concurrency config checks
1 parent 316af67 commit 2047a79

File tree

4 files changed

+23
-24
lines changed

4 files changed

+23
-24
lines changed

coverage/collector.py

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from typing import Any, Callable, TypeVar, cast
1515

1616
from coverage import env
17-
from coverage.config import CoverageConfig
1817
from coverage.core import Core
1918
from coverage.data import CoverageData
2019
from coverage.debug import short_stack
@@ -60,9 +59,6 @@ class Collector:
6059
# the top, and resumed when they become the top again.
6160
_collectors: list[Collector] = []
6261

63-
# The concurrency settings we support here.
64-
LIGHT_THREADS = {"greenlet", "eventlet", "gevent"}
65-
6662
def __init__(
6763
self,
6864
core: Core,
@@ -112,8 +108,7 @@ def __init__(
112108
self.file_mapper = file_mapper
113109
self.branch = branch
114110
self.warn = warn
115-
self.concurrency = concurrency
116-
assert isinstance(self.concurrency, list), f"Expected a list: {self.concurrency!r}"
111+
assert isinstance(concurrency, list), f"Expected a list: {concurrency!r}"
117112

118113
self.pid = os.getpid()
119114

@@ -125,37 +120,27 @@ def __init__(
125120

126121
self.concur_id_func = None
127122

128-
# We can handle a few concurrency options here, but only one at a time.
129-
concurrencies = set(self.concurrency)
130-
unknown = concurrencies - CoverageConfig.CONCURRENCY_CHOICES
131-
if unknown:
132-
show = ", ".join(sorted(unknown))
133-
raise ConfigError(f"Unknown concurrency choices: {show}")
134-
light_threads = concurrencies & self.LIGHT_THREADS
135-
if len(light_threads) > 1:
136-
show = ", ".join(sorted(light_threads))
137-
raise ConfigError(f"Conflicting concurrency settings: {show}")
138123
do_threading = False
139124

140125
tried = "nothing" # to satisfy pylint
141126
try:
142-
if "greenlet" in concurrencies:
127+
if "greenlet" in concurrency:
143128
tried = "greenlet"
144129
import greenlet
145130

146131
self.concur_id_func = greenlet.getcurrent
147-
elif "eventlet" in concurrencies:
132+
elif "eventlet" in concurrency:
148133
tried = "eventlet"
149134
import eventlet.greenthread
150135

151136
self.concur_id_func = eventlet.greenthread.getcurrent
152-
elif "gevent" in concurrencies:
137+
elif "gevent" in concurrency:
153138
tried = "gevent"
154139
import gevent
155140

156141
self.concur_id_func = gevent.getcurrent
157142

158-
if "thread" in concurrencies:
143+
if "thread" in concurrency:
159144
do_threading = True
160145
except ImportError as ex:
161146
msg = f"Couldn't trace with concurrency={tried}, the module isn't installed."
@@ -169,7 +154,7 @@ def __init__(
169154
),
170155
)
171156

172-
if do_threading or not concurrencies:
157+
if do_threading or not concurrency:
173158
# It's important to import threading only if we need it. If
174159
# it's imported early, and the program being measured uses
175160
# gevent, then gevent's monkey-patching won't work properly.

coverage/config.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,9 @@ def copy(self) -> CoverageConfig:
390390
"multiprocessing",
391391
}
392392

393+
# Mutually exclusive concurrency settings.
394+
LIGHT_THREADS = {"greenlet", "eventlet", "gevent"}
395+
393396
CONFIG_FILE_OPTIONS = [
394397
# These are *args for _set_attr_from_config_option:
395398
# (attr, where, type_="")
@@ -563,6 +566,17 @@ def post_process(self) -> None:
563566
if "subprocess" in self.patch:
564567
self.parallel = True
565568

569+
# We can handle a few concurrency options here, but only one at a time.
570+
concurrencies = set(self.concurrency)
571+
unknown = concurrencies - self.CONCURRENCY_CHOICES
572+
if unknown:
573+
show = ", ".join(sorted(unknown))
574+
raise ConfigError(f"Unknown concurrency choices: {show}")
575+
light_threads = concurrencies & self.LIGHT_THREADS
576+
if len(light_threads) > 1:
577+
show = ", ".join(sorted(light_threads))
578+
raise ConfigError(f"Conflicting concurrency settings: {show}")
579+
566580
def debug_info(self) -> list[tuple[str, Any]]:
567581
"""Make a list of (name, value) pairs for writing debug info."""
568582
return human_sorted_items((k, v) for k, v in self.__dict__.items() if not k.startswith("_"))

coverage/control.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ def load(self) -> None:
563563
def _init_for_start(self) -> None:
564564
"""Initialization for start()"""
565565
# Construct the collector.
566-
concurrency: list[str] = self.config.concurrency or []
566+
concurrency: list[str] = self.config.concurrency
567567
if "multiprocessing" in concurrency:
568568
if self.config.config_file is None:
569569
raise ConfigError("multiprocessing requires a configuration file")

tests/test_config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def test_toml_config_file(self) -> None:
8383
[tool.somethingelse]
8484
authors = ["Joe D'Ávila <[email protected]>"]
8585
[tool.coverage.run]
86-
concurrency = ["a", "b"]
86+
concurrency = ["thread", "eventlet"]
8787
timid = true
8888
data_file = ".hello_kitty.data"
8989
plugins = ["plugins.a_plugin"]
@@ -99,7 +99,7 @@ def test_toml_config_file(self) -> None:
9999
cov = coverage.Coverage()
100100
assert cov.config.timid
101101
assert not cov.config.branch
102-
assert cov.config.concurrency == ["a", "b"]
102+
assert cov.config.concurrency == ["thread", "eventlet"]
103103
assert cov.config.data_file == ".hello_kitty.data"
104104
assert cov.config.plugins == ["plugins.a_plugin"]
105105
assert cov.config.precision == 3

0 commit comments

Comments
 (0)