# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function)
from pkg_resources import parse_requirements, parse_version
import os
from operator import lt, le, eq, ne, ge, gt
import pytest
_relop = dict(zip('< <= == != >= >'.split(), (lt, le, eq, ne, ge, gt)))
[docs]class requires(object):
""" Conditional skipping (on requirements) of tests in pytest
Examples
--------
>>> @requires('numpy', 'scipy')
... def test_sqrt():
... import numpy as np
... assert np.sqrt(4) == 2
... from scipy.special import zeta
... assert zeta(2) < 2
...
>>> @requires('numpy>=1.9.0')
... def test_nanmedian():
... import numpy as np
... a = np.array([[10.0, 7, 4], [3, 2, 1]])
... a[0, 1] = np.nan
... assert np.nanmedian(a) == 3
...
"""
def __init__(self, *reqs):
self.missing = []
self.incomp = []
self.requirements = list(parse_requirements(reqs))
for req in self.requirements:
try:
mod = __import__(req.project_name)
except ImportError:
self.missing.append(req.project_name)
else:
try:
ver = parse_version(mod.__version__)
except AttributeError:
pass
else:
for rel, vstr in req.specs:
if not _relop[rel](ver, parse_version(vstr)):
self.incomp.append(str(req))
def __call__(self, cb):
r = 'Unfulfilled requirements.'
if self.missing:
r += " Missing modules: %s." % ', '.join(self.missing)
if self.incomp:
r += " Incomp versions: %s." % ', '.join(self.incomp)
return skipif(self.missing or self.incomp, reason=r)(cb)
[docs]def skipif(predicate, *, reason):
if os.environ.get('CHEMPY_SKIP_NO_TESTS', '0') == '1':
return pytest.mark.skipif(False, reason=reason)
else:
return pytest.mark.skipif(predicate, reason=reason)