Skip to content

Commit 602de0c

Browse files
committed
Begin multiprocessing misadventure
There is no per-instance state involved in USE_SHELL, so pickling is far less directly relevant than usual to multiprocessing: the spawn and forkserver methods will not preserve a subsequently changed attribute value unless side effects of loading a module (or other unpickling of a function or its arguments that are submitted to run on a worker subprocess) causes it to run again; the fork method will. This will be (automatically) the same with any combination of metaclasses, properties, and custom descriptors as in the more straightforward case of a simple class attribute. Subtleties arise in the code that uses GitPython and multiprocessing, but should not arise unintentionally from the change in implementation of USE_SHELL done to add deprecation warnings, except possibly with respect to whether warnings will be repeated in worker processes, which is less important than whether the actual state is preserved.
1 parent bf13888 commit 602de0c

File tree

1 file changed

+23
-5
lines changed

1 file changed

+23
-5
lines changed

test/deprecation/test_cmd_git.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
access are not inadvertently broken by mechanisms introduced to issue the warnings.
77
"""
88

9+
from concurrent.futures import ProcessPoolExecutor
910
import contextlib
1011
import sys
1112
from typing import Generator
@@ -36,7 +37,7 @@ def _suppress_deprecation_warning() -> Generator[None, None, None]:
3637

3738

3839
@pytest.fixture
39-
def try_restore_use_shell_state() -> Generator[None, None, None]:
40+
def restore_use_shell_state() -> Generator[None, None, None]:
4041
"""Fixture to attempt to restore state associated with the ``USE_SHELL`` attribute.
4142
4243
This is used to decrease the likelihood of state changes leaking out and affecting
@@ -142,7 +143,7 @@ def _assert_use_shell_full_results(
142143
assert recheck_message.startswith(_USE_SHELL_DEPRECATED_FRAGMENT)
143144

144145

145-
def test_use_shell_set_and_get_on_class(try_restore_use_shell_state: None) -> None:
146+
def test_use_shell_set_and_get_on_class(restore_use_shell_state: None) -> None:
146147
"""USE_SHELL can be set and re-read as a class attribute, always warning."""
147148
with pytest.deprecated_call() as setting:
148149
Git.USE_SHELL = True
@@ -163,7 +164,7 @@ def test_use_shell_set_and_get_on_class(try_restore_use_shell_state: None) -> No
163164
)
164165

165166

166-
def test_use_shell_set_on_class_get_on_instance(try_restore_use_shell_state: None) -> None:
167+
def test_use_shell_set_on_class_get_on_instance(restore_use_shell_state: None) -> None:
167168
"""USE_SHELL can be set on the class and read on an instance, always warning.
168169
169170
This is like test_use_shell_set_and_get_on_class but it performs reads on an
@@ -196,14 +197,31 @@ class (or an instance) is needed first before a read on an instance (or the clas
196197
@pytest.mark.parametrize("value", [False, True])
197198
def test_use_shell_cannot_set_on_instance(
198199
value: bool,
199-
try_restore_use_shell_state: None, # In case of a bug where it does set USE_SHELL.
200+
restore_use_shell_state: None, # In case of a bug where it does set USE_SHELL.
200201
) -> None:
201202
instance = Git()
202203
with pytest.raises(AttributeError):
203204
instance.USE_SHELL = value
204205

205206

206-
# FIXME: Test behavior with multiprocessing (the attribute needs to pickle properly).
207+
def _check_use_shell_in_worker(value: bool) -> None:
208+
# USE_SHELL should have the value set in the parent before starting the worker.
209+
assert Git.USE_SHELL is value
210+
211+
# FIXME: Check that mutation still works and raises the warning.
212+
213+
214+
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
215+
@pytest.mark.parametrize("value", [False, True])
216+
def test_use_shell_preserved_in_multiprocessing(
217+
value: bool,
218+
restore_use_shell_state: None,
219+
) -> None:
220+
"""The USE_SHELL class attribute pickles accurately for multiprocessing."""
221+
Git.USE_SHELL = value
222+
with ProcessPoolExecutor(max_workers=1) as executor:
223+
# Calling result() marshals any exception back to this process and raises it.
224+
executor.submit(_check_use_shell_in_worker, value).result()
207225

208226

209227
_EXPECTED_DIR_SUBSET = {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy