Source code for slash.core.requirements
from ..utils.python import resolve_underlying_function
_SLASH_REQUIRES_KEY_NAME = '__slash_requirements__'
[docs]def requires(req, message=None):
"""A decorator specifying that the decorated tests requires a certain precondition in order to run
:param req: Either a function receiving no arguments and returning a boolean, or a boolean specifying whether or not
the requirement is met
"""
if not isinstance(req, Requirement):
req = Requirement(req, message)
else:
assert message is None, 'Cannot specify message when passing Requirement objects to slash.requires'
def decorator(func_or_class):
reqs = _get_requirements_list(func_or_class)
reqs.append(req)
return func_or_class
return decorator
def _get_requirements_list(thing, create=True):
thing = resolve_underlying_function(thing)
existing = getattr(thing, _SLASH_REQUIRES_KEY_NAME, None)
key = id(thing)
if existing is None or key != existing[0]:
new_reqs = (key, [] if existing is None else existing[1][:])
if create:
setattr(thing, _SLASH_REQUIRES_KEY_NAME, new_reqs)
assert thing.__slash_requirements__ is new_reqs
returned = new_reqs[1]
else:
returned = existing[1]
return returned
def get_requirements(test):
return list(_get_requirements_list(test, create=False))
class Requirement(object):
def __init__(self, req, message=None):
super(Requirement, self).__init__()
self._req = req
self._message = message
def __repr__(self):
if self._message is not None:
return self._message
if isinstance(self._req, bool):
return '?'
if hasattr(self._req, '__name__'):
return '<{.__name__}>'.format(self._req)
return repr(self._req)
def is_met(self):
if isinstance(self._req, bool):
return self._req, self._message
returned = self._req()
if not isinstance(returned, tuple):
returned = (returned, self._message)
return returned
class Skip(Requirement):
"""
A special requirement used for implementing @slash.skipped
"""
def __init__(self, reason=None):
super(Skip, self).__init__(False, reason)
self.reason = reason