Skip to content

Commit 18aaa25

Browse files
browniebrokeauvipy
authored andcommitted
Remove case dependency
And copy required pytest fixtures from Celery celery/celery#7077
1 parent a18ac57 commit 18aaa25

File tree

2 files changed

+119
-1
lines changed

2 files changed

+119
-1
lines changed

requirements/test.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
case>=1.3.1
21
pytest>=6.2.5,<8
32
pytest-django>=4.5.2
43
pytest-benchmark

t/conftest.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
import sys
2+
import types
3+
from contextlib import contextmanager
4+
from unittest.mock import MagicMock, Mock, patch
5+
16
import pytest
27

38
# we have to import the pytest plugin fixtures here,
@@ -20,6 +25,9 @@
2025
)
2126

2227

28+
SENTINEL = object()
29+
30+
2331
@pytest.fixture(scope='session', autouse=True)
2432
def setup_default_app_trap():
2533
from celery._state import set_default_app
@@ -31,6 +39,117 @@ def app(celery_app):
3139
return celery_app
3240

3341

42+
@contextmanager
43+
def module_context_manager(*names):
44+
"""Mock one or modules such that every attribute is a :class:`Mock`."""
45+
yield from _module(*names)
46+
47+
48+
def _module(*names):
49+
prev = {}
50+
51+
class MockModule(types.ModuleType):
52+
53+
def __getattr__(self, attr):
54+
setattr(self, attr, Mock())
55+
return types.ModuleType.__getattribute__(self, attr)
56+
57+
mods = []
58+
for name in names:
59+
try:
60+
prev[name] = sys.modules[name]
61+
except KeyError:
62+
pass
63+
mod = sys.modules[name] = MockModule(name)
64+
mods.append(mod)
65+
try:
66+
yield mods
67+
finally:
68+
for name in names:
69+
try:
70+
sys.modules[name] = prev[name]
71+
except KeyError:
72+
try:
73+
del sys.modules[name]
74+
except KeyError:
75+
pass
76+
77+
78+
class _patching:
79+
80+
def __init__(self, monkeypatch, request):
81+
self.monkeypatch = monkeypatch
82+
self.request = request
83+
84+
def __getattr__(self, name):
85+
return getattr(self.monkeypatch, name)
86+
87+
def __call__(self, path, value=SENTINEL, name=None,
88+
new=MagicMock, **kwargs):
89+
value = self._value_or_mock(value, new, name, path, **kwargs)
90+
self.monkeypatch.setattr(path, value)
91+
return value
92+
93+
def object(self, target, attribute, *args, **kwargs):
94+
return _wrap_context(
95+
patch.object(target, attribute, *args, **kwargs),
96+
self.request)
97+
98+
def _value_or_mock(self, value, new, name, path, **kwargs):
99+
if value is SENTINEL:
100+
value = new(name=name or path.rpartition('.')[2])
101+
for k, v in kwargs.items():
102+
setattr(value, k, v)
103+
return value
104+
105+
def setattr(self, target, name=SENTINEL, value=SENTINEL, **kwargs):
106+
# alias to __call__ with the interface of pytest.monkeypatch.setattr
107+
if value is SENTINEL:
108+
value, name = name, None
109+
return self(target, value, name=name)
110+
111+
def setitem(self, dic, name, value=SENTINEL, new=MagicMock, **kwargs):
112+
# same as pytest.monkeypatch.setattr but default value is MagicMock
113+
value = self._value_or_mock(value, new, name, dic, **kwargs)
114+
self.monkeypatch.setitem(dic, name, value)
115+
return value
116+
117+
def modules(self, *mods):
118+
modules = []
119+
for mod in mods:
120+
mod = mod.split('.')
121+
modules.extend(reversed([
122+
'.'.join(mod[:-i] if i else mod) for i in range(len(mod))
123+
]))
124+
modules = sorted(set(modules))
125+
return _wrap_context(module_context_manager(*modules), self.request)
126+
127+
128+
def _wrap_context(context, request):
129+
ret = context.__enter__()
130+
131+
def fin():
132+
context.__exit__(*sys.exc_info())
133+
request.addfinalizer(fin)
134+
return ret
135+
136+
137+
@pytest.fixture()
138+
def patching(monkeypatch, request):
139+
"""Monkeypath.setattr shortcut.
140+
Example:
141+
.. code-block:: python
142+
>>> def test_foo(patching):
143+
>>> # execv value here will be mock.MagicMock by default.
144+
>>> execv = patching('os.execv')
145+
>>> patching('sys.platform', 'darwin') # set concrete value
146+
>>> patching.setenv('DJANGO_SETTINGS_MODULE', 'x.settings')
147+
>>> # val will be of type mock.MagicMock by default
148+
>>> val = patching.setitem('path.to.dict', 'KEY')
149+
"""
150+
return _patching(monkeypatch, request)
151+
152+
34153
@pytest.fixture(autouse=True)
35154
def test_cases_shortcuts(request, app, patching):
36155
if request.instance:

0 commit comments

Comments
 (0)