"""Testing utilities.""" import re SKIP_RE = re.compile("(\s*>>>.*?)(\s*)#\s*skip\s+if\s+(.*)$") def _assert_less(a, b, msg=None): message = "%r is not lower than %r" % (a, b) if msg is not None: message += ": " + msg assert a < b, message def _assert_greater(a, b, msg=None): message = "%r is not greater than %r" % (a, b) if msg is not None: message += ": " + msg assert a > b, message try: from nose.tools import assert_less except ImportError: assert_less = _assert_less try: from nose.tools import assert_greater except ImportError: assert_greater = _assert_greater def doctest_skip_parser(func): """ Decorator replaces custom skip test markup in doctests Say a function has a docstring:: >>> something # skip if not HAVE_AMODULE >>> something + else >>> something # skip if HAVE_BMODULE This decorator will evaluate the expresssion after ``skip if``. If this evaluates to True, then the comment is replaced by ``# doctest: +SKIP``. If False, then the comment is just removed. The expression is evaluated in the ``globals`` scope of `func`. For example, if the module global ``HAVE_AMODULE`` is False, and module global ``HAVE_BMODULE`` is False, the returned function will have docstring:: >>> something # doctest: +SKIP >>> something + else >>> something """ lines = func.__doc__.split('\n') new_lines = [] for line in lines: match = SKIP_RE.match(line) if match is None: new_lines.append(line) continue code, space, expr = match.groups() try: # Works as a function decorator if eval(expr, func.__globals__): code = code + space + "# doctest: +SKIP" except AttributeError: # Works as a class decorator if eval(expr, func.__init__.__globals__): code = code + space + "# doctest: +SKIP" new_lines.append(code) func.__doc__ = "\n".join(new_lines) return func