[svn r58308] * de-generalize conditional skips and only care

nicely for common tedious causes of skipping:
  import a module and checking it has a certain
  version.  usage example:

  docutils = py.test.importorskip(docutils, minversion="0.4")

* used new helper and cleanup skipping logic in py lib

--HG--
branch : trunk
This commit is contained in:
hpk 2008-09-21 17:15:28 +02:00
parent fa5c975c00
commit cc10d84088
17 changed files with 74 additions and 93 deletions

View File

@ -1,11 +1,10 @@
$Id: CHANGELOG 58297 2008-09-21 12:50:56Z hpk $ $Id: CHANGELOG 58308 2008-09-21 15:15:28Z hpk $
Changes between 0.9.2 and 1.0 (UNRELEASED) Changes between 0.9.2 and 1.0 (UNRELEASED)
============================================= =============================================
* py.test.skip(ifraises=execstring) allows to * new method: py.test.importorskip(mod,minversion)
conditionally skip, e.g. ifraises="import docutils" will either import or call py.test.skip()
will skip if there is no docutils installed.
* revised internal py.test architecture * revised internal py.test architecture

View File

@ -26,8 +26,8 @@ version = "1.0.0a1"
initpkg(__name__, initpkg(__name__,
description = "pylib and py.test: agile development and test support library", description = "pylib and py.test: agile development and test support library",
revision = int('$LastChangedRevision: 58190 $'.split(':')[1][:-1]), revision = int('$LastChangedRevision: 58308 $'.split(':')[1][:-1]),
lastchangedate = '$LastChangedDate: 2008-09-17 10:50:04 +0200 (Wed, 17 Sep 2008) $', lastchangedate = '$LastChangedDate: 2008-09-21 17:15:28 +0200 (Sun, 21 Sep 2008) $',
version = version, version = version,
url = "http://pylib.org", url = "http://pylib.org",
download_url = "http://codespeak.net/py/0.9.2/download.html", download_url = "http://codespeak.net/py/0.9.2/download.html",
@ -67,6 +67,7 @@ initpkg(__name__,
'test.raises' : ('./test/outcome.py', 'raises'), 'test.raises' : ('./test/outcome.py', 'raises'),
'test.deprecated_call' : ('./test/outcome.py', 'deprecated_call'), 'test.deprecated_call' : ('./test/outcome.py', 'deprecated_call'),
'test.skip' : ('./test/outcome.py', 'skip'), 'test.skip' : ('./test/outcome.py', 'skip'),
'test.importorskip' : ('./test/outcome.py', 'importorskip'),
'test.fail' : ('./test/outcome.py', 'fail'), 'test.fail' : ('./test/outcome.py', 'fail'),
'test.exit' : ('./test/outcome.py', 'exit'), 'test.exit' : ('./test/outcome.py', 'exit'),
'test.pdb' : ('./test/custompdb.py', 'set_trace'), 'test.pdb' : ('./test/custompdb.py', 'set_trace'),

View File

@ -61,10 +61,7 @@ def deindent(s, sep='\n'):
_initialized = False _initialized = False
def checkdocutils(): def checkdocutils():
global _initialized global _initialized
try: py.test.importorskip("docutils")
import docutils
except ImportError:
py.test.skip("docutils not importable")
if not _initialized: if not _initialized:
from py.__.rest import directive from py.__.rest import directive
directive.register_linkrole('api', resolve_linkrole) directive.register_linkrole('api', resolve_linkrole)

View File

@ -90,20 +90,17 @@ Skipping tests
---------------------------------------- ----------------------------------------
If you want to skip tests you can use ``py.test.skip`` within If you want to skip tests you can use ``py.test.skip`` within
test or setup functions. Examples:: test or setup functions. Example::
py.test.skip("message") py.test.skip("message")
py.test.skip(ifraises="import docutils")
py.test.skip(ifraises="""
import somepkg
assert somepkg.__version__.startswith("2")
""")
The first skip will cause unconditional skipping You can also use a helper to skip on a failing import::
The second skip will only cause skipping if
``docutils`` is not importable. docutils = py.test.importorskip("docutils")
The third form will cause skipping if ``somepkg``
is not importable or is not at least version "2". or to skip if the library does not have the right version::
docutils = py.test.importorskip("docutils", minversion="0.3")
automatic collection of tests on all levels automatic collection of tests on all levels
------------------------------------------- -------------------------------------------

View File

@ -181,7 +181,7 @@ class LocalPath(common.FSPathBase, PlatformMixin):
break break
for arg in strargs: for arg in strargs:
arg = arg.strip(sep) arg = arg.strip(sep)
if py.std.sys.platform == 'win32': if iswin32:
# allow unix style paths even on windows. # allow unix style paths even on windows.
arg = arg.strip('/') arg = arg.strip('/')
arg = arg.replace('/', sep) arg = arg.replace('/', sep)
@ -512,7 +512,7 @@ class LocalPath(common.FSPathBase, PlatformMixin):
if p.check(file=1): if p.check(file=1):
return p return p
else: else:
if py.std.sys.platform == 'win32': if iswin32:
paths = py.std.os.environ['Path'].split(';') paths = py.std.os.environ['Path'].split(';')
try: try:
systemroot = os.environ['SYSTEMROOT'] systemroot = os.environ['SYSTEMROOT']

View File

@ -7,6 +7,13 @@ from py.__.path.svn import cache, svncommon
mypath = py.magic.autopath() mypath = py.magic.autopath()
repodump = mypath.dirpath('repotest.dump') repodump = mypath.dirpath('repotest.dump')
def getsvnbin():
svnbin = py.path.local.sysfind('svn')
if svnbin is None:
py.test.skip("svn binary not found")
return svnbin
# make a wc directory out of a given root url # make a wc directory out of a given root url
# cache previously obtained wcs! # cache previously obtained wcs!
# #

View File

@ -95,6 +95,7 @@ class svnwc_no_svn(py.path.svnwc):
class TestSvnWCAuth(object): class TestSvnWCAuth(object):
def setup_method(self, meth): def setup_method(self, meth):
self.auth = SvnAuth('user', 'pass', cache_auth=False) self.auth = SvnAuth('user', 'pass', cache_auth=False)
svntestbase.getsvnbin()
def test_checkout(self): def test_checkout(self):
wc = svnwc_no_svn('foo', auth=self.auth) wc = svnwc_no_svn('foo', auth=self.auth)
@ -250,6 +251,7 @@ class TestSvnURLAuth(object):
class SvnAuthFunctionalTestBase(object): class SvnAuthFunctionalTestBase(object):
def setup_class(cls): def setup_class(cls):
svntestbase.getsvnbin()
if not option.runslowtests: if not option.runslowtests:
py.test.skip('skipping slow functional tests - use --runslowtests ' py.test.skip('skipping slow functional tests - use --runslowtests '
'to override') 'to override')

View File

@ -1,12 +1,10 @@
import py import py
from py.__.path.svn.testing.svntestbase import make_test_repo from py.__.path.svn.testing.svntestbase import make_test_repo, getsvnbin
if py.path.local.sysfind('svn') is None:
py.test.skip("cannot test py.path.svn, 'svn' binary not found")
class TestMakeRepo(object): class TestMakeRepo(object):
def setup_class(cls): def setup_class(cls):
getsvnbin()
cls.repo = make_test_repo() cls.repo = make_test_repo()
cls.wc = py.path.svnwc(py.test.ensuretemp("test-wc").join("wc")) cls.wc = py.path.svnwc(py.test.ensuretemp("test-wc").join("wc"))

View File

@ -1,13 +1,12 @@
import py import py
from py.__.path.svn.urlcommand import InfoSvnCommand from py.__.path.svn.urlcommand import InfoSvnCommand
from py.__.path.svn.testing.svntestbase import CommonCommandAndBindingTests, \ from py.__.path.svn.testing.svntestbase import CommonCommandAndBindingTests, \
getrepowc getrepowc, getsvnbin
import datetime import datetime
import time import time
def setup_module(mod): def setup_module(mod):
if py.path.local.sysfind('svn') is None: getsvnbin()
py.test.skip("cannot test py.path.svn, 'svn' binary not found")
class TestSvnURLCommandPath(CommonCommandAndBindingTests): class TestSvnURLCommandPath(CommonCommandAndBindingTests):
def setup_class(cls): def setup_class(cls):

View File

@ -1,6 +1,6 @@
import py import py
import sys import sys
from py.__.path.svn.testing.svntestbase import CommonSvnTests, getrepowc from py.__.path.svn.testing.svntestbase import CommonSvnTests, getrepowc, getsvnbin
from py.__.path.svn.wccommand import InfoSvnWCCommand, XMLWCStatus from py.__.path.svn.wccommand import InfoSvnWCCommand, XMLWCStatus
from py.__.path.svn.wccommand import parse_wcinfotime from py.__.path.svn.wccommand import parse_wcinfotime
from py.__.path.svn import svncommon from py.__.path.svn import svncommon
@ -22,8 +22,7 @@ else:
return os.path.normpath(os.path.normcase(p)) return os.path.normpath(os.path.normcase(p))
def setup_module(mod): def setup_module(mod):
if py.path.local.sysfind('svn') is None: getsvnbin()
py.test.skip("cannot test py.path.svn, 'svn' binary not found")
class TestWCSvnCommandPath(CommonSvnTests): class TestWCSvnCommandPath(CommonSvnTests):
def setup_class(cls): def setup_class(cls):

View File

@ -8,3 +8,4 @@ def getdata():
tmpdir = py.test.ensuretemp(rel.replace(pydir.sep, '_')) tmpdir = py.test.ensuretemp(rel.replace(pydir.sep, '_'))
mydatadir.copy(tmpdir) mydatadir.copy(tmpdir)
return tmpdir return tmpdir

View File

@ -1,13 +1,10 @@
import py import py
try:
import docutils
except ImportError:
py.test.skip("docutils not present")
from py.__.rest.testing.setup import getdata
docutils = py.test.importorskip("docutils")
from py.__.rest import directive from py.__.rest import directive
from py.__.misc import rest from py.__.misc import rest
from py.__.rest.latex import process_rest_file from py.__.rest.latex import process_rest_file
from py.__.rest.testing.setup import getdata
def setup_module(mod): def setup_module(mod):
mod.datadir = getdata() mod.datadir = getdata()

View File

@ -4,16 +4,13 @@ import py
from py.__.misc import rest from py.__.misc import rest
from py.__.rest.testing.setup import getdata from py.__.rest.testing.setup import getdata
def setup_module(mod): def setup_module(mod):
py.test.importorskip("docutils")
if not py.path.local.sysfind("gs") or \ if not py.path.local.sysfind("gs") or \
not py.path.local.sysfind("dot") or \ not py.path.local.sysfind("dot") or \
not py.path.local.sysfind("latex"): not py.path.local.sysfind("latex"):
py.test.skip("ghostscript, graphviz and latex needed") py.test.skip("ghostscript, graphviz and latex needed")
try:
import docutils
except ImportError:
py.test.skip("docutils not present")
mod.datadir = getdata() mod.datadir = getdata()
def test_process_simple(): def test_process_simple():

View File

@ -4,11 +4,7 @@ import py
from py.__.rest.latex import process_configfile, process_rest_file from py.__.rest.latex import process_configfile, process_rest_file
from py.__.rest.testing.setup import getdata from py.__.rest.testing.setup import getdata
try: docutils = py.test.importorskip("docutils")
import docutils
except ImportError:
py.test.skip("docutils not present")
def setup_module(mod): def setup_module(mod):
if not py.path.local.sysfind("gs") or \ if not py.path.local.sysfind("gs") or \

View File

@ -49,31 +49,30 @@ def exit(msg):
__tracebackhide__ = True __tracebackhide__ = True
raise Exit(msg) raise Exit(msg)
def skip(msg="", ifraises=None, ns=None): def skip(msg=""):
""" (conditionally) skip this test/module/conftest. """ skip with the given message. """
msg: use this message when skipping.
ifraises:
if "exec ifraises in {'py': py}" raises an exception
skip this test.
ns: use this namespace when executing ifraises
"""
__tracebackhide__ = True __tracebackhide__ = True
if ifraises is not None:
ifraises = py.code.Source(ifraises).compile()
if ns is None:
ns = {}
try:
exec ifraises in ns
except (KeyboardInterrupt, SystemExit):
raise
except Exception, e:
if not msg:
msg = repr(e)
else:
return
raise Skipped(msg=msg) raise Skipped(msg=msg)
def importorskip(modname, minversion=None):
""" return imported module or skip() """
compile(modname, '', 'eval') # to catch syntaxerrors
try:
mod = __import__(modname)
except ImportError:
py.test.skip("could not import %r" %(modname,))
if minversion is None:
return mod
verattr = getattr(mod, '__version__', None)
if isinstance(minversion, str):
minver = minversion.split(".")
else:
minver = list(minversion)
if verattr is None or verattr.split(".") < minver:
py.test.skip("module %r has __version__ %r, required is: %r" %(
modname, verattr, minversion))
return mod
def fail(msg="unknown failure"): def fail(msg="unknown failure"):
""" fail with the given Message. """ """ fail with the given Message. """
__tracebackhide__ = True __tracebackhide__ = True

View File

@ -387,7 +387,7 @@ class TestPyTest(AcceptBase):
class TestInteractive(AcceptBase): class TestInteractive(AcceptBase):
def getspawn(self): def getspawn(self):
py.test.skip(ifraises="import pexpect", ns=globals()) pexpect = py.test.importorskip("pexpect")
def spawn(cmd): def spawn(cmd):
return pexpect.spawn(cmd, logfile=self.tmpdir.join("spawn.out").open("w")) return pexpect.spawn(cmd, logfile=self.tmpdir.join("spawn.out").open("w"))
return spawn return spawn

View File

@ -59,33 +59,25 @@ def test_deprecated_explicit_call():
py.test.deprecated_call(dep_explicit, 0) py.test.deprecated_call(dep_explicit, 0)
py.test.deprecated_call(dep_explicit, 0) py.test.deprecated_call(dep_explicit, 0)
def test_skip_simple(): def test_skip_simple():
excinfo = py.test.raises(Skipped, 'py.test.skip("xxx")') excinfo = py.test.raises(Skipped, 'py.test.skip("xxx")')
assert excinfo.traceback[-1].frame.code.name == "skip" assert excinfo.traceback[-1].frame.code.name == "skip"
assert excinfo.traceback[-1].ishidden() assert excinfo.traceback[-1].ishidden()
def test_skip_ifraises(): def test_importorskip():
excinfo = py.test.raises(Skipped, '''
py.test.skip(ifraises="""
import lky
""")
''')
assert excinfo.traceback[-1].frame.code.name == "skip"
assert excinfo.traceback[-1].ishidden()
assert excinfo.value.msg.startswith("ImportError")
def test_skip_ifraises_ns():
d = {}
py.test.skip(ns=d, ifraises="import py")
assert d['py'] == py
def test_skip_ifraises_syntaxerror():
try: try:
excinfo = py.test.raises(SyntaxError, ''' sys = py.test.importorskip("sys")
py.test.skip(ifraises="x y z")''') assert sys == py.std.sys
#path = py.test.importorskip("os.path")
#assert path == py.std.os.path
py.test.raises(Skipped, "py.test.importorskip('alskdj')")
py.test.raises(SyntaxError, "py.test.importorskip('x y z')")
py.test.raises(SyntaxError, "py.test.importorskip('x=y')")
path = py.test.importorskip("py", minversion=".".join(py.__version__))
py.test.raises(Skipped, """
py.test.importorskip("py", minversion="5.0")
""")
except Skipped: except Skipped:
py.test.fail("should not skip") print py.code.ExceptionInfo()
assert not excinfo.traceback[-1].ishidden() py.test.fail("spurious skip")