Skip to content

Commit 279b247

Browse files
authored
Ensure only one tox environment operates on a packaging environment (#2588)
Resolves #2564
1 parent 932bb3e commit 279b247

File tree

3 files changed

+25
-8
lines changed

3 files changed

+25
-8
lines changed

docs/changelog/2564.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Ensure only on run environment operates at a time on a packaging environment (fixes unexpected failures when running in
2+
parallel mode) - by :user:`gaborbernat`.

src/tox/tox_env/package.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55

66
from abc import ABC, abstractmethod
77
from pathlib import Path
8-
from threading import Lock
9-
from typing import TYPE_CHECKING, Generator, Iterator, cast
8+
from threading import RLock
9+
from types import MethodType
10+
from typing import TYPE_CHECKING, Any, Callable, Generator, Iterator, cast
1011

1112
from tox.config.main import Config
1213
from tox.config.sets import EnvConfigSet
@@ -30,11 +31,26 @@ def __str__(self) -> str:
3031
return str(self.path)
3132

3233

34+
def _lock_method(lock: RLock, meth: Callable[..., Any]) -> Callable[..., Any]:
35+
def _func(*args: Any, **kwargs: Any) -> Any:
36+
with lock:
37+
return meth(*args, **kwargs)
38+
39+
return _func
40+
41+
3342
class PackageToxEnv(ToxEnv, ABC):
3443
def __init__(self, create_args: ToxEnvCreateArgs) -> None:
44+
self._lock = RLock()
3545
super().__init__(create_args)
3646
self._envs: set[str] = set()
37-
self._lock = Lock()
47+
48+
def __getattribute__(self, name: str) -> Any:
49+
# the packaging class might be used by multiple environments in parallel, hold a lock for operations on it
50+
obj = object.__getattribute__(self, name)
51+
if isinstance(obj, MethodType):
52+
obj = _lock_method(self._lock, obj)
53+
return obj
3854

3955
def register_config(self) -> None:
4056
super().register_config()
@@ -62,13 +78,11 @@ def register_run_env(self, run_env: RunToxEnv) -> Generator[tuple[str, str], Pac
6278
yield from () # empty generator by default
6379

6480
def mark_active_run_env(self, run_env: RunToxEnv) -> None:
65-
with self._lock:
66-
self._envs.add(run_env.conf.name)
81+
self._envs.add(run_env.conf.name)
6782

6883
def teardown_env(self, conf: EnvConfigSet) -> None:
69-
with self._lock:
70-
self._envs.remove(conf.name)
71-
has_envs = bool(self._envs)
84+
self._envs.remove(conf.name)
85+
has_envs = bool(self._envs)
7286
if not has_envs:
7387
self._teardown()
7488

whitelist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ fromdocname
7070
fromhex
7171
fs
7272
fullmatch
73+
getattribute
7374
getbasetemp
7475
getfqdn
7576
getitem

0 commit comments

Comments
 (0)