dynamicweb/cms/test_utils/util/context_managers.py

188 lines
4.9 KiB
Python

import sys
from contextlib import contextmanager
from io import StringIO
from shutil import rmtree as _rmtree
from tempfile import _exists, mkdtemp, template
from django.contrib.auth import get_user_model
from django.test.utils import override_settings
from django.utils.translation import activate, get_language
from cms.apphook_pool import apphook_pool
class NULL:
pass
class StdOverride:
def __init__(self, std='out', buffer=None):
self.std = std
self.buffer = buffer or StringIO()
def __enter__(self):
setattr(sys, 'std%s' % self.std, self.buffer)
return self.buffer
def __exit__(self, type, value, traceback):
setattr(sys, 'std%s' % self.std, getattr(sys, '__std%s__' % self.std))
class StdoutOverride(StdOverride):
"""
This overrides Python's the standard output and redirects it to a StringIO
object, so that on can test the output of the program.
example:
lines = None
with StdoutOverride() as buffer:
# print stuff
lines = buffer.getvalue()
"""
def __init__(self, buffer=None):
super().__init__('out', buffer)
class LanguageOverride:
def __init__(self, language):
self.newlang = language
def __enter__(self):
self.oldlang = get_language()
activate(self.newlang)
def __exit__(self, type, value, traceback):
activate(self.oldlang)
class TemporaryDirectory:
"""Create and return a temporary directory. This has the same
behavior as mkdtemp but can be used as a context manager. For
example:
with TemporaryDirectory() as tmpdir:
...
Upon exiting the context, the directory and everything contained
in it are removed.
"""
def __init__(self, suffix="", prefix=template, dir=None):
self.name = mkdtemp(suffix, prefix, dir)
def __enter__(self):
return self.name
def cleanup(self):
if _exists(self.name):
_rmtree(self.name)
def __exit__(self, exc, value, tb):
self.cleanup()
class UserLoginContext:
def __init__(self, testcase, user):
self.testcase = testcase
self.user = user
def __enter__(self):
loginok = self.testcase.client.login(username=getattr(self.user, get_user_model().USERNAME_FIELD),
password=getattr(self.user, get_user_model().USERNAME_FIELD))
self.old_user = getattr(self.testcase, 'user', None)
self.testcase.user = self.user
self.testcase.assertTrue(loginok)
def __exit__(self, exc, value, tb):
self.testcase.user = self.old_user
if not self.testcase.user:
delattr(self.testcase, 'user')
self.testcase.client.logout()
class ChangeModel:
"""
Changes attributes on a model while within the context.
These changes *ARE* saved to the database for the context!
"""
def __init__(self, instance, **overrides):
self.instance = instance
self.overrides = overrides
def __enter__(self):
self.old = {}
for key, value in self.overrides.items():
self.old[key] = getattr(self.instance, key, NULL)
setattr(self.instance, key, value)
self.instance.save()
def __exit__(self, exc, value, tb):
for key in self.overrides.keys():
old_value = self.old[key]
if old_value is NULL:
delattr(self.instance, key)
else:
setattr(self.instance, key, old_value)
self.instance.save()
@contextmanager
def disable_logger(logger):
old = logger.disabled
logger.disabled = True
yield
logger.disabled = old
@contextmanager
def apphooks(*hooks):
_apphooks = apphook_pool.apphooks
_apps = apphook_pool.apps
_discovered = apphook_pool.discovered
apphook_pool.clear()
for hook in hooks:
apphook_pool.register(hook)
try:
yield
finally:
apphook_pool.apphooks = _apphooks
apphook_pool.apps = _apps
apphook_pool.discovered = _discovered
@contextmanager
def signal_tester(*signals):
env = SignalTester()
for signal in signals:
signal.connect(env)
try:
yield env
finally:
for signal in signals:
signal.disconnect(env)
class SignalTester:
def __init__(self):
self.call_count = 0
self.calls = []
def __call__(self, *args, **kwargs):
self.call_count += 1
self.calls.append((args, kwargs))
@contextmanager
def override_placeholder_conf(CMS_PLACEHOLDER_CONF):
from cms.utils.placeholder import _clear_placeholder_conf_cache
# Call _get_placeholder_settings after changing the setting
with override_settings(CMS_PLACEHOLDER_CONF=CMS_PLACEHOLDER_CONF):
_clear_placeholder_conf_cache() # Clear cache if needed
yield
# Call _get_placeholder_settings after resetting the setting
_clear_placeholder_conf_cache() # Clear cache if needed