pip/tests/unit/test_utils_parallel.py

74 lines
2.3 KiB
Python
Raw Normal View History

2020-05-25 17:00:04 +02:00
"""Test multiprocessing/multithreading higher-order functions."""
from contextlib import contextmanager
2020-06-03 18:15:34 +02:00
from importlib import import_module
2020-05-25 17:00:04 +02:00
from math import factorial
2020-06-03 18:15:34 +02:00
from sys import modules
from typing import Any, Iterator
2020-05-25 17:00:04 +02:00
import pytest
2020-05-25 17:00:04 +02:00
2021-08-13 15:23:45 +02:00
DUNDER_IMPORT = "builtins.__import__"
2020-05-25 17:00:04 +02:00
FUNC, ITERABLE = factorial, range(42)
2021-08-13 15:23:45 +02:00
MAPS = "map_multiprocess", "map_multithread"
2020-06-03 18:15:34 +02:00
_import = __import__
def unload_parallel() -> None:
2020-06-03 18:15:34 +02:00
try:
2021-08-13 15:23:45 +02:00
del modules["pip._internal.utils.parallel"]
except KeyError:
pass
@contextmanager
def tmp_import_parallel() -> Iterator[Any]:
unload_parallel()
try:
2021-08-13 15:23:45 +02:00
yield import_module("pip._internal.utils.parallel")
finally:
unload_parallel()
2020-05-25 17:00:04 +02:00
def lack_sem_open(name: str, *args: Any, **kwargs: Any) -> Any:
2020-05-25 17:00:04 +02:00
"""Raise ImportError on import of multiprocessing.synchronize."""
2021-08-13 15:23:45 +02:00
if name.endswith("synchronize"):
2020-05-25 17:00:04 +02:00
raise ImportError
2020-06-03 18:15:34 +02:00
return _import(name, *args, **kwargs)
def have_sem_open(name: str, *args: Any, **kwargs: Any) -> Any:
2020-06-03 18:15:34 +02:00
"""Make sure multiprocessing.synchronize import is successful."""
# We don't care about the return value
# since we don't use the pool with this import.
2021-08-13 15:23:45 +02:00
if name.endswith("synchronize"):
return None
2020-06-03 18:15:34 +02:00
return _import(name, *args, **kwargs)
2020-05-25 17:00:04 +02:00
@pytest.mark.parametrize("name", MAPS)
def test_lack_sem_open(name: str, monkeypatch: pytest.MonkeyPatch) -> None:
2020-05-25 17:00:04 +02:00
"""Test fallback when sem_open is not available.
If so, multiprocessing[.dummy].Pool will fail to be created and
2020-06-03 18:15:34 +02:00
map_async should fallback to map.
2020-05-25 17:00:04 +02:00
"""
2020-06-03 18:15:34 +02:00
monkeypatch.setattr(DUNDER_IMPORT, lack_sem_open)
with tmp_import_parallel() as parallel:
assert getattr(parallel, name) is parallel._map_fallback
2020-06-03 18:15:34 +02:00
@pytest.mark.parametrize("name", MAPS)
def test_have_sem_open(name: str, monkeypatch: pytest.MonkeyPatch) -> None:
2020-06-03 18:15:34 +02:00
"""Test fallback when sem_open is available."""
monkeypatch.setattr(DUNDER_IMPORT, have_sem_open)
with tmp_import_parallel() as parallel:
2021-08-13 15:23:45 +02:00
assert getattr(parallel, name) is getattr(parallel, f"_{name}")
2020-06-03 18:15:34 +02:00
@pytest.mark.parametrize("name", MAPS)
def test_map(name: str) -> None:
2020-06-03 18:15:34 +02:00
"""Test correctness of result of asynchronous maps."""
2021-08-13 15:23:45 +02:00
map_async = getattr(import_module("pip._internal.utils.parallel"), name)
2020-06-03 18:15:34 +02:00
assert set(map_async(FUNC, ITERABLE)) == set(map(FUNC, ITERABLE))