ÿØÿà JFIF ` ` ÿþxØ
| Server IP : 109.234.164.53 / Your IP : 216.73.216.110 Web Server : Apache System : Linux cervelle.o2switch.net 4.18.0-553.32.1.lve.el8.x86_64 #1 SMP Thu Dec 19 13:14:03 UTC 2024 x86_64 User : computer3 ( 1098) PHP Version : 7.1.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /proc/thread-self/root/opt/alt/python37/lib/python3.7/site-packages/testfixtures/ |
Upload File : |
# Copyright (c) 2008-2013 Simplistix Ltd, 2016 Chris Withers
# See license.txt for license details.
from functools import partial
from testfixtures.compat import ClassType
from testfixtures.resolve import resolve, not_there
from testfixtures.utils import wrap, extend_docstring
import warnings
def not_same_descriptor(x, y, descriptor):
return isinstance(x, descriptor) and not isinstance(y, descriptor)
class Replacer:
"""
These are used to manage the mocking out of objects so that units
of code can be tested without having to rely on their normal
dependencies.
"""
def __init__(self):
self.originals = {}
def _replace(self, container, name, method, value, strict=True):
if value is not_there:
if method == 'a':
delattr(container, name)
if method == 'i':
del container[name]
else:
if method == 'a':
setattr(container, name, value)
if method == 'i':
container[name] = value
def __call__(self, target, replacement, strict=True):
"""
Replace the specified target with the supplied replacement.
"""
container, method, attribute, t_obj = resolve(target)
if method is None:
raise ValueError('target must contain at least one dot!')
if t_obj is not_there and strict:
raise AttributeError('Original %r not found' % attribute)
if t_obj is not_there and replacement is not_there:
return not_there
replacement_to_use = replacement
if isinstance(container, (type, ClassType)):
if not_same_descriptor(t_obj, replacement, classmethod):
replacement_to_use = classmethod(replacement)
elif not_same_descriptor(t_obj, replacement, staticmethod):
replacement_to_use = staticmethod(replacement)
self._replace(container, attribute, method, replacement_to_use, strict)
if target not in self.originals:
self.originals[target] = t_obj
return replacement
def replace(self, target, replacement, strict=True):
"""
Replace the specified target with the supplied replacement.
"""
self(target, replacement, strict)
def restore(self):
"""
Restore all the original objects that have been replaced by
calls to the :meth:`replace` method of this :class:`Replacer`.
"""
for target, original in tuple(self.originals.items()):
container, method, attribute, found = resolve(target)
self._replace(container, attribute, method, original, strict=False)
del self.originals[target]
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.restore()
def __del__(self):
if self.originals:
# no idea why coverage misses the following statement
# it's covered by test_replace.TestReplace.test_replacer_del
warnings.warn( # pragma: no cover
'Replacer deleted without being restored, '
'originals left: %r' % self.originals
)
def replace(target, replacement, strict=True):
"""
A decorator to replace a target object for the duration of a test
function.
"""
r = Replacer()
return wrap(partial(r.__call__, target, replacement, strict), r.restore)
class Replace(object):
"""
A context manager that uses a :class:`Replacer` to replace a single target.
"""
def __init__(self, target, replacement, strict=True):
self.target = target
self.replacement = replacement
self.strict = strict
self._replacer = Replacer()
def __enter__(self):
return self._replacer(self.target, self.replacement, self.strict)
def __exit__(self, exc_type, exc_val, exc_tb):
self._replacer.restore()
replace_params_doc = """
:param target: A string containing the dotted-path to the
object to be replaced. This path may specify a
module in a package, an attribute of a module,
or any attribute of something contained within
a module.
:param replacement: The object to use as a replacement.
:param strict: When `True`, an exception will be raised if an
attempt is made to replace an object that does
not exist.
"""
# add the param docs, so we only have one copy of them!
extend_docstring(replace_params_doc,
[Replacer.__call__, Replacer.replace, replace, Replace])