-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconftest.py
92 lines (66 loc) · 2.59 KB
/
conftest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
from __future__ import annotations
import shutil
import sys
from contextlib import contextmanager
from pathlib import Path
from typing import Callable
import pytest
from click.testing import CliRunner
from pytask import storage
ROOT = Path(__file__).parent.joinpath("..").resolve()
needs_julia = pytest.mark.skipif(
shutil.which("julia") is None,
reason="julia needs to be installed.",
)
parametrize_parse_code_serializer_suffix = pytest.mark.parametrize(
("parse_config_code", "serializer", "suffix"),
[
("import JSON; config = JSON.parse(read(ARGS[1], String))", "json", ".json"),
("import YAML; config = YAML.load_file(ARGS[1])", "yaml", ".yaml"),
],
)
class SysPathsSnapshot:
"""A snapshot for sys.path."""
def __init__(self) -> None:
self.__saved = sys.path.copy(), sys.meta_path.copy()
def restore(self) -> None:
sys.path[:], sys.meta_path[:] = self.__saved
class SysModulesSnapshot:
"""A snapshot for sys.modules."""
def __init__(self, preserve: Callable[[str], bool] | None = None) -> None:
self.__preserve = preserve
self.__saved = sys.modules.copy()
def restore(self) -> None:
if self.__preserve:
self.__saved.update(
(k, m) for k, m in sys.modules.items() if self.__preserve(k)
)
sys.modules.clear()
sys.modules.update(self.__saved)
@contextmanager
def restore_sys_path_and_module_after_test_execution():
sys_path_snapshot = SysPathsSnapshot()
sys_modules_snapshot = SysModulesSnapshot()
yield
sys_modules_snapshot.restore()
sys_path_snapshot.restore()
@pytest.fixture(autouse=True)
def _restore_sys_path_and_module_after_test_execution():
"""Restore sys.path and sys.modules after every test execution.
This fixture became necessary because most task modules in the tests are named
`task_example`. Since the change in #424, the same module is not reimported which
solves errors with parallelization. At the same time, modules with the same name in
the tests are overshadowing another and letting tests fail.
The changes to `sys.path` might not be necessary to restore, but we do it anyways.
"""
with restore_sys_path_and_module_after_test_execution():
yield
class CustomCliRunner(CliRunner):
def invoke(self, *args, **kwargs):
"""Restore sys.path and sys.modules after an invocation."""
storage.create()
with restore_sys_path_and_module_after_test_execution():
return super().invoke(*args, **kwargs)
@pytest.fixture
def runner():
return CustomCliRunner()