commit
523380432a
13
CHANGELOG
13
CHANGELOG
|
@ -5,10 +5,15 @@ Changes between 1.0.0 and 1.0.1
|
||||||
nose-style function/method/generator setup/teardown and
|
nose-style function/method/generator setup/teardown and
|
||||||
tries to report functions correctly.
|
tries to report functions correctly.
|
||||||
|
|
||||||
* unicode fixes: capturing and unicode writes to sys.stdout
|
* capturing of unicode writes or encoded strings to sys.stdout/err
|
||||||
(through e.g a print statement) now work within tests,
|
work better, also terminalwriting was adapted and somewhat
|
||||||
they are encoded as "utf8" by default, also terminalwriting
|
unified between windows and linux.
|
||||||
was adapted and somewhat unified between windows and linux
|
|
||||||
|
* improved documentation layout and content a lot
|
||||||
|
|
||||||
|
* added a "--help-config" option to show conftest.py / ENV-var names for
|
||||||
|
all longopt cmdline options, and some special conftest.py variables.
|
||||||
|
renamed 'conf_capture' conftest setting to 'option_capture' accordingly.
|
||||||
|
|
||||||
* fix issue #27: better reporting on non-collectable items given on commandline
|
* fix issue #27: better reporting on non-collectable items given on commandline
|
||||||
(e.g. pyc files)
|
(e.g. pyc files)
|
||||||
|
|
27
MANIFEST
27
MANIFEST
|
@ -3,9 +3,15 @@ LICENSE
|
||||||
MANIFEST
|
MANIFEST
|
||||||
README.txt
|
README.txt
|
||||||
_findpy.py
|
_findpy.py
|
||||||
|
bin-for-dist/all-plat.sh
|
||||||
|
bin-for-dist/gendoc.py
|
||||||
|
bin-for-dist/genscripts.py
|
||||||
|
bin-for-dist/gensetup.py
|
||||||
|
bin-for-dist/makepluginlist.py
|
||||||
doc/announce/release-0.9.0.txt
|
doc/announce/release-0.9.0.txt
|
||||||
doc/announce/release-0.9.2.txt
|
doc/announce/release-0.9.2.txt
|
||||||
doc/announce/release-1.0.0.txt
|
doc/announce/release-1.0.0.txt
|
||||||
|
doc/announce/release-1.0.1.txt
|
||||||
doc/announce/releases.txt
|
doc/announce/releases.txt
|
||||||
doc/bin.txt
|
doc/bin.txt
|
||||||
doc/code.txt
|
doc/code.txt
|
||||||
|
@ -14,6 +20,7 @@ doc/conftest.py
|
||||||
doc/contact.txt
|
doc/contact.txt
|
||||||
doc/download.txt
|
doc/download.txt
|
||||||
doc/execnet.txt
|
doc/execnet.txt
|
||||||
|
doc/faq.txt
|
||||||
doc/img/pylib.png
|
doc/img/pylib.png
|
||||||
doc/index.txt
|
doc/index.txt
|
||||||
doc/io.txt
|
doc/io.txt
|
||||||
|
@ -22,21 +29,26 @@ doc/misc.txt
|
||||||
doc/path.txt
|
doc/path.txt
|
||||||
doc/style.css
|
doc/style.css
|
||||||
doc/test/attic.txt
|
doc/test/attic.txt
|
||||||
doc/test/config.txt
|
doc/test/config.html
|
||||||
|
doc/test/customize.txt
|
||||||
doc/test/dist.txt
|
doc/test/dist.txt
|
||||||
doc/test/examples.txt
|
doc/test/examples.txt
|
||||||
doc/test/extend.txt
|
doc/test/extend.html
|
||||||
doc/test/features.txt
|
doc/test/features.txt
|
||||||
doc/test/funcargs.txt
|
doc/test/funcargs.txt
|
||||||
|
doc/test/index.txt
|
||||||
|
doc/test/mission.txt
|
||||||
doc/test/plugin/capture.txt
|
doc/test/plugin/capture.txt
|
||||||
doc/test/plugin/doctest.txt
|
doc/test/plugin/doctest.txt
|
||||||
doc/test/plugin/figleaf.txt
|
doc/test/plugin/figleaf.txt
|
||||||
|
doc/test/plugin/helpconfig.txt
|
||||||
doc/test/plugin/hooklog.txt
|
doc/test/plugin/hooklog.txt
|
||||||
doc/test/plugin/hookspec.txt
|
doc/test/plugin/hookspec.txt
|
||||||
doc/test/plugin/index.txt
|
doc/test/plugin/index.txt
|
||||||
doc/test/plugin/keyword.txt
|
doc/test/plugin/keyword.txt
|
||||||
doc/test/plugin/links.txt
|
doc/test/plugin/links.txt
|
||||||
doc/test/plugin/monkeypatch.txt
|
doc/test/plugin/monkeypatch.txt
|
||||||
|
doc/test/plugin/nose.txt
|
||||||
doc/test/plugin/oejskit.txt
|
doc/test/plugin/oejskit.txt
|
||||||
doc/test/plugin/pastebin.txt
|
doc/test/plugin/pastebin.txt
|
||||||
doc/test/plugin/pdb.txt
|
doc/test/plugin/pdb.txt
|
||||||
|
@ -48,7 +60,7 @@ doc/test/plugin/unittest.txt
|
||||||
doc/test/plugin/xfail.txt
|
doc/test/plugin/xfail.txt
|
||||||
doc/test/quickstart.txt
|
doc/test/quickstart.txt
|
||||||
doc/test/talks.txt
|
doc/test/talks.txt
|
||||||
doc/test/test.txt
|
doc/test/test.html
|
||||||
doc/test/xunit_setup.txt
|
doc/test/xunit_setup.txt
|
||||||
doc/xml.txt
|
doc/xml.txt
|
||||||
example/assertion/failure_demo.py
|
example/assertion/failure_demo.py
|
||||||
|
@ -80,13 +92,10 @@ example/funcarg/test_simpleprovider.py
|
||||||
example/genhtml.py
|
example/genhtml.py
|
||||||
example/genhtmlcss.py
|
example/genhtmlcss.py
|
||||||
example/genxml.py
|
example/genxml.py
|
||||||
makepluginlist.py
|
|
||||||
py/LICENSE
|
py/LICENSE
|
||||||
py/__init__.py
|
py/__init__.py
|
||||||
py/_com.py
|
py/_com.py
|
||||||
py/bin/_findpy.py
|
py/bin/_findpy.py
|
||||||
py/bin/_genscripts.py
|
|
||||||
py/bin/gendoc.py
|
|
||||||
py/bin/py.cleanup
|
py/bin/py.cleanup
|
||||||
py/bin/py.countloc
|
py/bin/py.countloc
|
||||||
py/bin/py.lookup
|
py/bin/py.lookup
|
||||||
|
@ -239,6 +248,7 @@ py/misc/testing/test_cache.py
|
||||||
py/misc/testing/test_com.py
|
py/misc/testing/test_com.py
|
||||||
py/misc/testing/test_error.py
|
py/misc/testing/test_error.py
|
||||||
py/misc/testing/test_initpkg.py
|
py/misc/testing/test_initpkg.py
|
||||||
|
py/misc/testing/test_install.py
|
||||||
py/misc/testing/test_std.py
|
py/misc/testing/test_std.py
|
||||||
py/misc/testing/test_svnlook.py
|
py/misc/testing/test_svnlook.py
|
||||||
py/misc/testing/test_terminal.py
|
py/misc/testing/test_terminal.py
|
||||||
|
@ -342,9 +352,11 @@ py/test/plugin/pytest_default.py
|
||||||
py/test/plugin/pytest_doctest.py
|
py/test/plugin/pytest_doctest.py
|
||||||
py/test/plugin/pytest_execnetcleanup.py
|
py/test/plugin/pytest_execnetcleanup.py
|
||||||
py/test/plugin/pytest_figleaf.py
|
py/test/plugin/pytest_figleaf.py
|
||||||
|
py/test/plugin/pytest_helpconfig.py
|
||||||
py/test/plugin/pytest_hooklog.py
|
py/test/plugin/pytest_hooklog.py
|
||||||
py/test/plugin/pytest_keyword.py
|
py/test/plugin/pytest_keyword.py
|
||||||
py/test/plugin/pytest_monkeypatch.py
|
py/test/plugin/pytest_monkeypatch.py
|
||||||
|
py/test/plugin/pytest_nose.py
|
||||||
py/test/plugin/pytest_pastebin.py
|
py/test/plugin/pytest_pastebin.py
|
||||||
py/test/plugin/pytest_pdb.py
|
py/test/plugin/pytest_pdb.py
|
||||||
py/test/plugin/pytest_pylint.py
|
py/test/plugin/pytest_pylint.py
|
||||||
|
@ -358,6 +370,8 @@ py/test/plugin/pytest_tmpdir.py
|
||||||
py/test/plugin/pytest_unittest.py
|
py/test/plugin/pytest_unittest.py
|
||||||
py/test/plugin/pytest_xfail.py
|
py/test/plugin/pytest_xfail.py
|
||||||
py/test/plugin/test_pytest_capture.py
|
py/test/plugin/test_pytest_capture.py
|
||||||
|
py/test/plugin/test_pytest_helpconfig.py
|
||||||
|
py/test/plugin/test_pytest_nose.py
|
||||||
py/test/plugin/test_pytest_runner.py
|
py/test/plugin/test_pytest_runner.py
|
||||||
py/test/plugin/test_pytest_runner_xunit.py
|
py/test/plugin/test_pytest_runner_xunit.py
|
||||||
py/test/plugin/test_pytest_terminal.py
|
py/test/plugin/test_pytest_terminal.py
|
||||||
|
@ -379,7 +393,6 @@ py/test/testing/test_conftesthandle.py
|
||||||
py/test/testing/test_deprecated_api.py
|
py/test/testing/test_deprecated_api.py
|
||||||
py/test/testing/test_funcargs.py
|
py/test/testing/test_funcargs.py
|
||||||
py/test/testing/test_genitems.py
|
py/test/testing/test_genitems.py
|
||||||
py/test/testing/test_install.py
|
|
||||||
py/test/testing/test_outcome.py
|
py/test/testing/test_outcome.py
|
||||||
py/test/testing/test_parseopt.py
|
py/test/testing/test_parseopt.py
|
||||||
py/test/testing/test_pickling.py
|
py/test/testing/test_pickling.py
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
py.test --dist=each $* \
|
||||||
|
--tx 'popen//python=python2.6' \
|
||||||
|
--tx 'ssh=noco//python=/usr/local/bin/python2.4//chdir=/tmp/pytest-python2.4' \
|
||||||
|
--tx 'socket=192.168.1.106:8888'
|
|
@ -1,5 +1,7 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
XXX
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
from _findpy import py
|
from _findpy import py
|
|
@ -1,6 +1,7 @@
|
||||||
from _findpy import py
|
from _findpy import py
|
||||||
|
|
||||||
mydir = py.magic.autopath().dirpath()
|
bindir = py.magic.autopath().dirpath().dirpath("py").join("bin")
|
||||||
|
assert bindir.check(), bindir
|
||||||
|
|
||||||
def getbasename(name):
|
def getbasename(name):
|
||||||
assert name[:2] == "py"
|
assert name[:2] == "py"
|
||||||
|
@ -8,7 +9,7 @@ def getbasename(name):
|
||||||
|
|
||||||
def genscript_unix(name):
|
def genscript_unix(name):
|
||||||
basename = getbasename(name)
|
basename = getbasename(name)
|
||||||
path = mydir.join(basename)
|
path = bindir.join(basename)
|
||||||
path.write(py.code.Source("""
|
path.write(py.code.Source("""
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from _findpy import py
|
from _findpy import py
|
||||||
|
@ -19,7 +20,7 @@ def genscript_unix(name):
|
||||||
def genscript_windows(name):
|
def genscript_windows(name):
|
||||||
basename = getbasename(name)
|
basename = getbasename(name)
|
||||||
winbasename = basename + ".cmd"
|
winbasename = basename + ".cmd"
|
||||||
path = mydir.join("win32").join(winbasename)
|
path = bindir.join("win32").join(winbasename)
|
||||||
path.write(py.code.Source("""
|
path.write(py.code.Source("""
|
||||||
@echo off
|
@echo off
|
||||||
python "%%~dp0\..\%s" %%*
|
python "%%~dp0\..\%s" %%*
|
|
@ -0,0 +1,342 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, sys.argv[1])
|
||||||
|
import py
|
||||||
|
|
||||||
|
toolpath = py.magic.autopath()
|
||||||
|
binpath = py.path.local(py.__file__).dirpath('bin')
|
||||||
|
|
||||||
|
def error(msg):
|
||||||
|
print >>sys.stderr, msg
|
||||||
|
raise SystemExit, 1
|
||||||
|
|
||||||
|
def reformat(text):
|
||||||
|
return " ".join(text.split())
|
||||||
|
|
||||||
|
class SetupWriter(object):
|
||||||
|
EXCLUDES = ("MANIFEST.in", "contrib")
|
||||||
|
|
||||||
|
def __init__(self, basedir, pkg, setuptools=False):
|
||||||
|
self.basedir = basedir
|
||||||
|
self.setuptools = setuptools
|
||||||
|
assert self.basedir.check()
|
||||||
|
self.pkg = pkg
|
||||||
|
self.meta = pkg.__pkg__
|
||||||
|
self.lines = []
|
||||||
|
self.allpaths = self.getallpath(self.basedir)
|
||||||
|
|
||||||
|
def getallpath(self, basedir):
|
||||||
|
contrib = self.basedir.join("contrib")
|
||||||
|
allpath = []
|
||||||
|
lines = py.process.cmdexec("hg st -mcan").split("\n")
|
||||||
|
for path in lines:
|
||||||
|
p = basedir.join(path)
|
||||||
|
assert p.check(), p
|
||||||
|
if not p.relto(contrib) and p != contrib and not self.isexcluded(p):
|
||||||
|
allpath.append(p)
|
||||||
|
return allpath
|
||||||
|
|
||||||
|
def append(self, string):
|
||||||
|
lines = string.split("\n")
|
||||||
|
while lines:
|
||||||
|
if not lines[0].strip():
|
||||||
|
lines.pop(0)
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
if not lines:
|
||||||
|
self.lines.append("")
|
||||||
|
return
|
||||||
|
line = lines[0]
|
||||||
|
indent = len(line) - len(line.lstrip())
|
||||||
|
for line in lines:
|
||||||
|
if line.strip():
|
||||||
|
assert not line[:indent].strip(), line
|
||||||
|
line = line[indent:]
|
||||||
|
self.lines.append(line)
|
||||||
|
|
||||||
|
def write_winfuncs(self):
|
||||||
|
self.append('''
|
||||||
|
''')
|
||||||
|
|
||||||
|
def tip_info(self, indent=8):
|
||||||
|
old = self.basedir.chdir()
|
||||||
|
indent = " " * indent
|
||||||
|
try:
|
||||||
|
info = []
|
||||||
|
output = py.process.cmdexec(
|
||||||
|
"hg tip --template '" # tags: {tags}\n"
|
||||||
|
#"branch: {branches}\n"
|
||||||
|
"revision: {rev}:{node}\n'"
|
||||||
|
)
|
||||||
|
for line in output.split("\n"):
|
||||||
|
info.append("%s %s" %(indent, line.strip()))
|
||||||
|
return "\n".join(info)
|
||||||
|
finally:
|
||||||
|
old.chdir()
|
||||||
|
|
||||||
|
def setup_header(self):
|
||||||
|
#tooltime = "%s %s" %(py.std.time.asctime(), py.std.time.tzname[0])
|
||||||
|
toolname = toolpath.basename
|
||||||
|
#toolrevision = py.path.svnwc(toolpath).info().rev
|
||||||
|
|
||||||
|
pkgname = self.pkg.__name__
|
||||||
|
info = self.tip_info()
|
||||||
|
self.append('''
|
||||||
|
"""
|
||||||
|
py lib / py.test setup.py file, autogenerated by %(toolname)s
|
||||||
|
''' % locals())
|
||||||
|
#self.append(info)
|
||||||
|
self.append('''
|
||||||
|
"""
|
||||||
|
import os, sys
|
||||||
|
''')
|
||||||
|
|
||||||
|
if self.setuptools:
|
||||||
|
#import ez_setup
|
||||||
|
#ez_setup.use_setuptools()
|
||||||
|
self.append("""
|
||||||
|
from setuptools import setup
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
self.append("""
|
||||||
|
from distutils.core import setup
|
||||||
|
""")
|
||||||
|
|
||||||
|
def setup_trailer(self):
|
||||||
|
self.append('''
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
''')
|
||||||
|
|
||||||
|
def setup_function(self):
|
||||||
|
params = self.__dict__.copy()
|
||||||
|
params.update(self.meta.__dict__)
|
||||||
|
#params['url'] = self.wcinfo.url
|
||||||
|
#params['rev'] = self.wcinfo.rev
|
||||||
|
#params['long_description'] = reformat(params['long_description'])
|
||||||
|
#print py.std.pprint.pprint(params)
|
||||||
|
self.append('long_description = """')
|
||||||
|
for line in params['long_description'].split('\n'):
|
||||||
|
self.append(line)
|
||||||
|
self.append('"""')
|
||||||
|
trunk = None
|
||||||
|
if params['version'] == 'trunk':
|
||||||
|
trunk = 'trunk'
|
||||||
|
self.append('trunk = %r' % trunk)
|
||||||
|
self.append('''
|
||||||
|
def main():
|
||||||
|
setup(
|
||||||
|
name=%(name)r,
|
||||||
|
description=%(description)r,
|
||||||
|
long_description = long_description,
|
||||||
|
version= trunk or %(version)r,
|
||||||
|
url=%(url)r,
|
||||||
|
license=%(license)r,
|
||||||
|
platforms=%(platforms)r,
|
||||||
|
author=%(author)r,
|
||||||
|
author_email=%(author_email)r,
|
||||||
|
''' % params)
|
||||||
|
indent = " " * 8
|
||||||
|
#self.append_pprint(indent, py_modules=['_findpy',]),
|
||||||
|
#self.append_pprint(indent, scripts=self.getscripts())
|
||||||
|
self.append_pprint(indent, entry_points={'console_scripts':self.getconsolescripts()})
|
||||||
|
self.append_pprint(indent, classifiers=self.meta.classifiers)
|
||||||
|
self.append_pprint(indent, packages=self.getpackages())
|
||||||
|
#self.append_pprint(indent, data_files=self.getdatafiles())
|
||||||
|
self.append_pprint(indent, package_data=self.getpackagedata())
|
||||||
|
#self.append_pprint(indent, package_dir={'py': 'py'})
|
||||||
|
#self.append_pprint(indent, packages=self.getpackages())
|
||||||
|
if self.setuptools:
|
||||||
|
self.append_pprint(indent, zip_safe=False)
|
||||||
|
self.lines.append(indent[4:] + ")\n")
|
||||||
|
|
||||||
|
def setup_scripts(self):
|
||||||
|
# XXX this was used for a different approach
|
||||||
|
not used
|
||||||
|
self.append("""
|
||||||
|
def getscripts():
|
||||||
|
if sys.platform == "win32":
|
||||||
|
base = "py/bin/win32/"
|
||||||
|
ext = ".cmd"
|
||||||
|
else:
|
||||||
|
base = "py/bin/"
|
||||||
|
ext = ""
|
||||||
|
l = []
|
||||||
|
for name in %r:
|
||||||
|
l.append(base + name + ext)
|
||||||
|
return l
|
||||||
|
""" % ([script.basename for script in binpath.listdir("py.*")]))
|
||||||
|
|
||||||
|
def append_pprint(self, indent, append=",", **kw):
|
||||||
|
for name, value in kw.items():
|
||||||
|
stringio = py.std.StringIO.StringIO()
|
||||||
|
value = py.std.pprint.pprint(value, stream=stringio)
|
||||||
|
stringio.seek(0)
|
||||||
|
lines = stringio.readlines()
|
||||||
|
line = lines.pop(0).rstrip()
|
||||||
|
self.lines.append(indent + "%s=%s" %(name, line))
|
||||||
|
indent = indent + " " * (len(name)+1)
|
||||||
|
for line in lines:
|
||||||
|
self.lines.append(indent + line.rstrip())
|
||||||
|
self.lines[-1] = self.lines[-1] + append
|
||||||
|
|
||||||
|
def getconsolescripts(self):
|
||||||
|
bindir = self.basedir.join('py', 'bin')
|
||||||
|
scripts = []
|
||||||
|
for p in self.allpaths:
|
||||||
|
if p.dirpath() == bindir:
|
||||||
|
if p.basename.startswith('py.'):
|
||||||
|
shortname = "py" + p.basename[3:]
|
||||||
|
scripts.append("%s = py.cmdline:%s" %
|
||||||
|
(p.basename, shortname))
|
||||||
|
return scripts
|
||||||
|
|
||||||
|
def getscripts(self):
|
||||||
|
bindir = self.basedir.join('py', 'bin')
|
||||||
|
scripts = []
|
||||||
|
for p in self.allpaths:
|
||||||
|
if p.dirpath() == bindir:
|
||||||
|
if p.basename.startswith('py.'):
|
||||||
|
scripts.append(p.relto(self.basedir))
|
||||||
|
return scripts
|
||||||
|
|
||||||
|
def getpackages(self):
|
||||||
|
packages = []
|
||||||
|
for p in self.allpaths: # contains no directories!
|
||||||
|
#if p.basename == "py":
|
||||||
|
# continue
|
||||||
|
if p.dirpath('__init__.py').check():
|
||||||
|
modpath = p.dirpath().relto(self.basedir).replace(p.sep, '.')
|
||||||
|
if modpath != "py" and not modpath.startswith("py."):
|
||||||
|
continue
|
||||||
|
if modpath in packages:
|
||||||
|
continue
|
||||||
|
for exclude in self.EXCLUDES:
|
||||||
|
if modpath.startswith(exclude):
|
||||||
|
print "EXCLUDING", modpath
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
packages.append(modpath)
|
||||||
|
packages.sort()
|
||||||
|
return packages
|
||||||
|
|
||||||
|
def getpackagedata(self):
|
||||||
|
datafiles = []
|
||||||
|
pkgbase = self.basedir.join(self.pkg.__name__)
|
||||||
|
for p in self.allpaths:
|
||||||
|
if p.check(file=1) and (not p.dirpath("__init__.py").check()
|
||||||
|
or p.ext != ".py"):
|
||||||
|
if p.dirpath() != self.basedir:
|
||||||
|
x = p.relto(pkgbase)
|
||||||
|
if x:
|
||||||
|
datafiles.append(p.relto(pkgbase))
|
||||||
|
return {'py': datafiles}
|
||||||
|
|
||||||
|
def getdatafiles(self):
|
||||||
|
datafiles = []
|
||||||
|
for p in self.allpaths:
|
||||||
|
if p.check(file=1) and not p.ext == ".py":
|
||||||
|
if p.dirpath() != self.basedir:
|
||||||
|
datafiles.append(p.relto(self.basedir))
|
||||||
|
return datafiles
|
||||||
|
|
||||||
|
def setup_win32(self):
|
||||||
|
import winpath
|
||||||
|
self.append(py.std.inspect.getsource(winpath))
|
||||||
|
self.append("""
|
||||||
|
from distutils.command.install import install
|
||||||
|
class my_install(install):
|
||||||
|
def finalize_other(self):
|
||||||
|
install.finalize_other(self)
|
||||||
|
on_win32_add_to_PATH()
|
||||||
|
cmdclass = {'install': my_install}
|
||||||
|
""")
|
||||||
|
|
||||||
|
def setup_win32(self):
|
||||||
|
self.append(r'''
|
||||||
|
# scripts for windows: turn "py.SCRIPT" into "py_SCRIPT" and create
|
||||||
|
# "py.SCRIPT.cmd" files invoking "py_SCRIPT"
|
||||||
|
from distutils.command.install_scripts import install_scripts
|
||||||
|
class my_install_scripts(install_scripts):
|
||||||
|
def run(self):
|
||||||
|
install_scripts.run(self)
|
||||||
|
#print self.outfiles
|
||||||
|
for fn in self.outfiles:
|
||||||
|
basename = os.path.basename(fn)
|
||||||
|
if basename.startswith("py.") and not basename.endswith(".cmd"):
|
||||||
|
newbasename = basename.replace(".", "_")
|
||||||
|
newfn = os.path.join(os.path.dirname(fn), newbasename)
|
||||||
|
if os.path.exists(newfn):
|
||||||
|
os.remove(newfn)
|
||||||
|
os.rename(fn, newfn)
|
||||||
|
fncmd = fn + ".cmd"
|
||||||
|
if os.path.exists(fncmd):
|
||||||
|
os.remove(fncmd)
|
||||||
|
f = open(fncmd, 'w')
|
||||||
|
f.write("@echo off\n")
|
||||||
|
f.write('python "%%~dp0\%s" %%*' %(newbasename))
|
||||||
|
f.close()
|
||||||
|
if sys.platform == "win32":
|
||||||
|
cmdclass = {'install_scripts': my_install_scripts}
|
||||||
|
else:
|
||||||
|
cmdclass = {}
|
||||||
|
''')
|
||||||
|
|
||||||
|
def write_setup(self):
|
||||||
|
self.setup_header()
|
||||||
|
self.setup_function()
|
||||||
|
#self.setup_scripts()
|
||||||
|
#self.setup_win32()
|
||||||
|
self.setup_trailer()
|
||||||
|
targetfile = self.basedir.join("setup.py")
|
||||||
|
targetfile.write("\n".join(self.lines))
|
||||||
|
print "wrote", targetfile
|
||||||
|
|
||||||
|
def isexcluded(self, wcpath):
|
||||||
|
return wcpath.basename[0] == "."
|
||||||
|
rel = wcpath.relto(self.basedir)
|
||||||
|
if rel.find("testing") != -1:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def write_manifest(self):
|
||||||
|
lines = []
|
||||||
|
for p in self.allpaths:
|
||||||
|
if p.check(dir=1):
|
||||||
|
continue
|
||||||
|
toadd = p.relto(self.basedir)
|
||||||
|
if toadd:
|
||||||
|
for exclude in self.EXCLUDES:
|
||||||
|
if toadd.startswith(exclude):
|
||||||
|
break
|
||||||
|
assert toadd.find(exclude) == -1, (toadd, exclude)
|
||||||
|
else:
|
||||||
|
lines.append("%s" %(toadd))
|
||||||
|
lines.sort()
|
||||||
|
targetfile = self.basedir.join("MANIFEST")
|
||||||
|
targetfile.write("\n".join(lines))
|
||||||
|
print "wrote", targetfile
|
||||||
|
|
||||||
|
def write_all(self):
|
||||||
|
self.write_manifest()
|
||||||
|
self.write_setup()
|
||||||
|
|
||||||
|
def parseargs():
|
||||||
|
basedir = py.path.local(sys.argv[1])
|
||||||
|
if not basedir.check():
|
||||||
|
error("basedir not found: %s" %(basedir,))
|
||||||
|
pydir = basedir.join('py')
|
||||||
|
if not pydir.check():
|
||||||
|
error("no 'py' directory found in: %s" %(pydir,))
|
||||||
|
actualpydir = py.path.local(py.__file__).dirpath()
|
||||||
|
if pydir != actualpydir:
|
||||||
|
error("package dir conflict, %s != %s" %(pydir, actualpydir))
|
||||||
|
return basedir
|
||||||
|
|
||||||
|
def main(basedir=None):
|
||||||
|
if basedir is None:
|
||||||
|
basedir = parseargs()
|
||||||
|
writer = SetupWriter(basedir, py, setuptools=True)
|
||||||
|
writer.write_all()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -4,14 +4,16 @@ import sys
|
||||||
WIDTH = 75
|
WIDTH = 75
|
||||||
|
|
||||||
plugins = [
|
plugins = [
|
||||||
('Plugins related to Python test functions and programs',
|
('plugins for Python test functions',
|
||||||
'xfail figleaf monkeypatch capture recwarn',),
|
'xfail figleaf monkeypatch capture recwarn',),
|
||||||
('Plugins for other testing styles and languages',
|
('plugins for other testing styles and languages',
|
||||||
'oejskit unittest nose doctest restdoc'),
|
'oejskit unittest nose doctest restdoc'),
|
||||||
('Plugins for generic reporting and failure logging',
|
('plugins for generic reporting and failure logging',
|
||||||
'pastebin resultlog terminal',),
|
'pastebin resultlog terminal',),
|
||||||
('internal plugins / core functionality',
|
('plugins for generic reporting and failure logging',
|
||||||
'pdb keyword hooklog')
|
'pastebin resultlog terminal',),
|
||||||
|
('misc plugins / core functionality',
|
||||||
|
'helpconfig pdb keyword hooklog')
|
||||||
#('internal plugins / core functionality',
|
#('internal plugins / core functionality',
|
||||||
# #'pdb keyword hooklog runner execnetcleanup # pytester',
|
# #'pdb keyword hooklog runner execnetcleanup # pytester',
|
||||||
# 'pdb keyword hooklog runner execnetcleanup' # pytester',
|
# 'pdb keyword hooklog runner execnetcleanup' # pytester',
|
||||||
|
@ -194,24 +196,25 @@ class PluginDoc(RestWriter):
|
||||||
# basename))
|
# basename))
|
||||||
self.h1("Start improving this plugin in 30 seconds")
|
self.h1("Start improving this plugin in 30 seconds")
|
||||||
self.para(py.code.Source("""
|
self.para(py.code.Source("""
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `%s`_ plugin source code
|
1. Download `%s`_ plugin source code
|
||||||
2. put it somewhere as ``%s`` into your import path
|
2. put it somewhere as ``%s`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
""" % (basename, basename)))
|
""" % (basename, basename)))
|
||||||
# your work appreciated if you offer back your version. In this case
|
# your work appreciated if you offer back your version. In this case
|
||||||
# it probably makes sense if you `checkout the py.test
|
# it probably makes sense if you `checkout the py.test
|
||||||
# development version`_ and apply your changes to the plugin
|
# development version`_ and apply your changes to the plugin
|
||||||
# version in there.
|
# version in there.
|
||||||
|
#self.links.append((basename,
|
||||||
|
# "http://bitbucket.org/hpk42/py-trunk/raw/%s/"
|
||||||
|
# "py/test/plugin/%s" %(hg_changeset, basename)))
|
||||||
self.links.append((basename,
|
self.links.append((basename,
|
||||||
"http://bitbucket.org/hpk42/py-trunk/raw/%s/"
|
"http://bitbucket.org/hpk42/py-trunk/raw/%s/"
|
||||||
"py/test/plugin/%s" %(hg_changeset, basename)))
|
"py/test/plugin/%s" %(pyversion, basename)))
|
||||||
self.links.append(('extend', '../extend.html'))
|
self.links.append(('customize', '../customize.html'))
|
||||||
self.links.append(('plugins', 'index.html'))
|
self.links.append(('plugins', 'index.html'))
|
||||||
self.links.append(('contact', '../../contact.html'))
|
self.links.append(('get in contact', '../../contact.html'))
|
||||||
self.links.append(('checkout the py.test development version',
|
self.links.append(('checkout the py.test development version',
|
||||||
'../../download.html#checkout'))
|
'../../download.html#checkout'))
|
||||||
|
|
||||||
|
@ -269,6 +272,7 @@ if __name__ == "__main__":
|
||||||
_config.pluginmanager.do_configure(_config)
|
_config.pluginmanager.do_configure(_config)
|
||||||
|
|
||||||
pydir = py.path.local(py.__file__).dirpath()
|
pydir = py.path.local(py.__file__).dirpath()
|
||||||
|
pyversion = py.version
|
||||||
|
|
||||||
cmd = "hg tip --template '{node}'"
|
cmd = "hg tip --template '{node}'"
|
||||||
old = pydir.dirpath().chdir()
|
old = pydir.dirpath().chdir()
|
|
@ -0,0 +1,48 @@
|
||||||
|
1.0.1: improved reporting, nose/unittest.py support, bug fixes
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
This is a bugfix release of pylib/py.test also coming with:
|
||||||
|
|
||||||
|
* improved documentation, improved navigation
|
||||||
|
* test failure reporting improvements
|
||||||
|
* support for directly running existing nose/unittest.py style tests
|
||||||
|
|
||||||
|
visit here for more info, including quickstart and tutorials:
|
||||||
|
|
||||||
|
http://pytest.org and http://pylib.org
|
||||||
|
|
||||||
|
|
||||||
|
Changelog 1.0.0 to 1.0.1
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
* added a default 'pytest_nose' plugin which handles nose.SkipTest,
|
||||||
|
nose-style function/method/generator setup/teardown and
|
||||||
|
tries to report functions correctly.
|
||||||
|
|
||||||
|
* improved documentation, better navigation: see http://pytest.org
|
||||||
|
|
||||||
|
* added a "--help-config" option to show conftest.py / ENV-var names for
|
||||||
|
all longopt cmdline options, and some special conftest.py variables.
|
||||||
|
renamed 'conf_capture' conftest setting to 'option_capture' accordingly.
|
||||||
|
|
||||||
|
* unicode fixes: capturing and unicode writes to sys.stdout
|
||||||
|
(through e.g a print statement) now work within tests,
|
||||||
|
they are encoded as "utf8" by default, also terminalwriting
|
||||||
|
was adapted and somewhat unified between windows and linux
|
||||||
|
|
||||||
|
* fix issue #27: better reporting on non-collectable items given on commandline
|
||||||
|
(e.g. pyc files)
|
||||||
|
|
||||||
|
* fix issue #33: added --version flag (thanks Benjamin Peterson)
|
||||||
|
|
||||||
|
* fix issue #32: adding support for "incomplete" paths to wcpath.status()
|
||||||
|
|
||||||
|
* "Test" prefixed classes are *not* collected by default anymore if they
|
||||||
|
have an __init__ method
|
||||||
|
|
||||||
|
* monkeypatch setenv() now accepts a "prepend" parameter
|
||||||
|
|
||||||
|
* improved reporting of collection error tracebacks
|
||||||
|
|
||||||
|
* simplified multicall mechanism and plugin architecture,
|
||||||
|
renamed some internal methods and argnames
|
|
@ -15,7 +15,7 @@ available on your command prompt.
|
||||||
The ``py.test`` executable is the main entry point into the py-lib testing tool,
|
The ``py.test`` executable is the main entry point into the py-lib testing tool,
|
||||||
see the `py.test documentation`_.
|
see the `py.test documentation`_.
|
||||||
|
|
||||||
.. _`py.test documentation`: test/test.html
|
.. _`py.test documentation`: test/index.html
|
||||||
|
|
||||||
``py.cleanup``
|
``py.cleanup``
|
||||||
==============
|
==============
|
||||||
|
@ -51,6 +51,7 @@ prepended.
|
||||||
|
|
||||||
Usage: ``py.rest [PATHS] [options]``
|
Usage: ``py.rest [PATHS] [options]``
|
||||||
|
|
||||||
|
[deprecated in 1.0, will likely be separated]
|
||||||
Loot recursively for .txt files starting from ``PATHS`` and convert them to
|
Loot recursively for .txt files starting from ``PATHS`` and convert them to
|
||||||
html using docutils or to pdf files, if the ``--pdf`` option is used. For
|
html using docutils or to pdf files, if the ``--pdf`` option is used. For
|
||||||
conversion to PDF you will need several command line tools, on Ubuntu Linux
|
conversion to PDF you will need several command line tools, on Ubuntu Linux
|
||||||
|
|
|
@ -45,9 +45,9 @@ pageTracker._trackPageview();
|
||||||
|
|
||||||
def a_docref(self, name, relhtmlpath):
|
def a_docref(self, name, relhtmlpath):
|
||||||
docpath = self.project.docpath
|
docpath = self.project.docpath
|
||||||
return html.a(name, class_="menu",
|
return html.div(html.a(name, class_="menu",
|
||||||
href=relpath(self.targetpath.strpath,
|
href=relpath(self.targetpath.strpath,
|
||||||
docpath.join(relhtmlpath).strpath))
|
docpath.join(relhtmlpath).strpath)))
|
||||||
|
|
||||||
def a_apigenref(self, name, relhtmlpath):
|
def a_apigenref(self, name, relhtmlpath):
|
||||||
apipath = self.project.apigenpath
|
apipath = self.project.apigenpath
|
||||||
|
@ -57,19 +57,30 @@ pageTracker._trackPageview();
|
||||||
|
|
||||||
def fill_menubar(self):
|
def fill_menubar(self):
|
||||||
items = [
|
items = [
|
||||||
|
self.a_docref("install", "download.html"),
|
||||||
|
self.a_docref("contact", "contact.html"),
|
||||||
|
self.a_docref("faq", "faq.html"),
|
||||||
|
html.div(
|
||||||
|
html.h3("py.test:"),
|
||||||
|
self.a_docref("doc index", "test/index.html"),
|
||||||
|
self.a_docref("features", "test/features.html"),
|
||||||
|
self.a_docref("quickstart", "test/quickstart.html"),
|
||||||
|
self.a_docref("tutorials", "test/talks.html"),
|
||||||
|
self.a_docref("plugins", "test/plugin/index.html"),
|
||||||
|
self.a_docref("funcargs", "test/funcargs.html"),
|
||||||
|
self.a_docref("customize", "test/customize.html"),
|
||||||
|
),
|
||||||
|
html.div(
|
||||||
|
html.h3("supporting APIs:"),
|
||||||
self.a_docref("pylib index", "index.html"),
|
self.a_docref("pylib index", "index.html"),
|
||||||
self.a_docref("test doc-index", "test/test.html"),
|
|
||||||
self.a_docref("test quickstart", "test/quickstart.html"),
|
|
||||||
self.a_docref("test features", "test/features.html"),
|
|
||||||
self.a_docref("test plugins", "test/plugin/index.html"),
|
|
||||||
self.a_docref("py.execnet", "execnet.html"),
|
self.a_docref("py.execnet", "execnet.html"),
|
||||||
|
self.a_docref("py.path", "path.html"),
|
||||||
|
self.a_docref("py.code", "code.html"),
|
||||||
|
)
|
||||||
#self.a_docref("py.code", "code.html"),
|
#self.a_docref("py.code", "code.html"),
|
||||||
#self.a_apigenref("api", "api/index.html"),
|
#self.a_apigenref("api", "api/index.html"),
|
||||||
#self.a_apigenref("source", "source/index.html"),
|
#self.a_apigenref("source", "source/index.html"),
|
||||||
#self.a_href("source", "http://bitbucket.org/hpk42/py-trunk/src/"),
|
#self.a_href("source", "http://bitbucket.org/hpk42/py-trunk/src/"),
|
||||||
self.a_href("issues", "http://bitbucket.org/hpk42/py-trunk/issues/"),
|
|
||||||
self.a_docref("contact", "contact.html"),
|
|
||||||
self.a_docref("install", "download.html"),
|
|
||||||
]
|
]
|
||||||
self.menubar = html.div(id=css.menubar, *[
|
self.menubar = html.div(id=css.menubar, *[
|
||||||
html.div(item) for item in items])
|
html.div(item) for item in items])
|
||||||
|
|
|
@ -3,3 +3,5 @@ import py
|
||||||
#py.test.importorskip("pygments")
|
#py.test.importorskip("pygments")
|
||||||
pytest_plugins = ['pytest_restdoc']
|
pytest_plugins = ['pytest_restdoc']
|
||||||
rsyncdirs = ['.']
|
rsyncdirs = ['.']
|
||||||
|
|
||||||
|
collect_ignore = ['test/attic.txt']
|
||||||
|
|
|
@ -5,9 +5,12 @@ Contact and Communication points
|
||||||
|
|
||||||
- #pylib on irc.freenode.net IRC channel for random questions.
|
- #pylib on irc.freenode.net IRC channel for random questions.
|
||||||
|
|
||||||
|
|
||||||
- `tetamap`_: Holger Krekel's blog, often about testing and py.test related news.
|
- `tetamap`_: Holger Krekel's blog, often about testing and py.test related news.
|
||||||
|
|
||||||
- `py-svn general commit mailing list`_ to follow development commits,
|
- `Testing In Python`_: a mailing list for testing tools and discussion.
|
||||||
|
|
||||||
|
- `commit mailing list`_ or `@pylibcommit`_ to follow development commits,
|
||||||
|
|
||||||
- `bitbucket issue tracker`_ use this bitbucket issue tracker to report
|
- `bitbucket issue tracker`_ use this bitbucket issue tracker to report
|
||||||
bugs or request features.
|
bugs or request features.
|
||||||
|
@ -22,6 +25,8 @@ Contact and Communication points
|
||||||
|
|
||||||
.. _tetamap: http://tetamap.wordpress.com
|
.. _tetamap: http://tetamap.wordpress.com
|
||||||
|
|
||||||
|
.. _`@pylibcommit`: http://twitter.com/pylibcommit
|
||||||
|
|
||||||
|
|
||||||
..
|
..
|
||||||
get an account on codespeak
|
get an account on codespeak
|
||||||
|
@ -33,14 +38,13 @@ Contact and Communication points
|
||||||
you are new to the python developer community please come to the IRC
|
you are new to the python developer community please come to the IRC
|
||||||
or the mailing list and ask questions, get involved.
|
or the mailing list and ask questions, get involved.
|
||||||
|
|
||||||
|
.. _`Testing in Python`: http://lists.idyll.org/listinfo/testing-in-python
|
||||||
.. _FOAF: http://en.wikipedia.org/wiki/FOAF
|
.. _FOAF: http://en.wikipedia.org/wiki/FOAF
|
||||||
.. _us: http://codespeak.net/mailman/listinfo/py-dev
|
.. _us: http://codespeak.net/mailman/listinfo/py-dev
|
||||||
.. _codespeak: http://codespeak.net/
|
.. _codespeak: http://codespeak.net/
|
||||||
.. _`py-dev`:
|
.. _`py-dev`:
|
||||||
.. _`development mailing list`:
|
.. _`development mailing list`:
|
||||||
.. _`py-dev developers list`: http://codespeak.net/mailman/listinfo/py-dev
|
.. _`py-dev developers list`: http://codespeak.net/mailman/listinfo/py-dev
|
||||||
.. _`subversion commit mailing list`:
|
|
||||||
.. _`py-svn`:
|
.. _`py-svn`:
|
||||||
.. _`py-svn general commit mailing list`: http://codespeak.net/mailman/listinfo/py-svn
|
.. _`commit mailing list`: http://codespeak.net/mailman/listinfo/py-svn
|
||||||
.. _`development bug/feature tracker`: https://codespeak.net/issue/py-dev/
|
|
||||||
|
|
||||||
|
|
106
doc/download.txt
106
doc/download.txt
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
Latest Release, see `PyPI project page`_
|
Latest Release, see `PyPI project page`_
|
||||||
|
|
||||||
using setuptools / easy_install
|
using easy_install
|
||||||
===================================================
|
===================================================
|
||||||
|
|
||||||
With a working `setuptools installation`_ you can type::
|
With a working `setuptools installation`_ you can type::
|
||||||
|
@ -16,16 +16,11 @@ With a working `setuptools installation`_ you can type::
|
||||||
|
|
||||||
to get the latest release of the py lib. The ``-U`` switch
|
to get the latest release of the py lib. The ``-U`` switch
|
||||||
will trigger an upgrade if you already have an older version installed.
|
will trigger an upgrade if you already have an older version installed.
|
||||||
|
On Linux systems you may need to execute the command as superuser and
|
||||||
|
on Windows you might need to write down the full path to ``easy_install``.
|
||||||
The py lib and its tools are expected to work well on Linux,
|
The py lib and its tools are expected to work well on Linux,
|
||||||
Windows and OSX, Python versions 2.3, 2.4, 2.5 and 2.6.
|
Windows and OSX, Python versions 2.3, 2.4, 2.5 and 2.6.
|
||||||
|
|
||||||
We provide binary eggs for Windows machines.
|
|
||||||
|
|
||||||
On other systems you need a working C-compiler in order to
|
|
||||||
install the full py lib. If you don't have a compiler available
|
|
||||||
you can still install the py lib but without greenlets - look
|
|
||||||
below for the ``install_lib`` target.
|
|
||||||
|
|
||||||
**IMPORTANT NOTE**: if you are using Windows and have
|
**IMPORTANT NOTE**: if you are using Windows and have
|
||||||
0.8 versions of the py lib on your system, please download
|
0.8 versions of the py lib on your system, please download
|
||||||
and execute http://codespeak.net/svn/py/build/winpathclean.py
|
and execute http://codespeak.net/svn/py/build/winpathclean.py
|
||||||
|
@ -36,9 +31,11 @@ You can find out the py lib version with::
|
||||||
print py.version
|
print py.version
|
||||||
|
|
||||||
|
|
||||||
.. _`checkout`:
|
.. _mercurial: http://mercurial.selenic.com/wiki/
|
||||||
|
.. _checkout:
|
||||||
|
.. _tarball:
|
||||||
|
|
||||||
Installing from version control / develop mode
|
Working from version control or a tarball
|
||||||
=================================================
|
=================================================
|
||||||
|
|
||||||
To follow development or help with fixing things
|
To follow development or help with fixing things
|
||||||
|
@ -47,41 +44,59 @@ and documentation source with mercurial_::
|
||||||
|
|
||||||
hg clone https://bitbucket.org/hpk42/py-trunk/
|
hg clone https://bitbucket.org/hpk42/py-trunk/
|
||||||
|
|
||||||
With a working `setuptools installation`_ you can then issue::
|
This currrently contains a 1.0.x branch and the
|
||||||
|
default 'trunk' branch where mainline development
|
||||||
|
takes place. There also is a readonly subversion
|
||||||
|
checkout available::
|
||||||
|
|
||||||
|
svn co https://codespeak.net/svn/py/dist
|
||||||
|
|
||||||
|
You can also go to the python package index and
|
||||||
|
download and unpack a TAR file::
|
||||||
|
|
||||||
|
http://pypi.python.org/pypi/py/
|
||||||
|
|
||||||
|
activating checkout with setuptools
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
With a working `setuptools installation`_ you can issue::
|
||||||
|
|
||||||
python setup.py develop
|
python setup.py develop
|
||||||
|
|
||||||
in order to work with your checkout version.
|
in order to work with the tools and the lib of your checkout.
|
||||||
|
|
||||||
For enhancing one of the plugins you may go to
|
|
||||||
the ``py/test/plugin/`` sub directory.
|
|
||||||
|
|
||||||
.. _mercurial: http://mercurial.selenic.com/wiki/
|
|
||||||
|
|
||||||
.. _`no-setuptools`:
|
.. _`no-setuptools`:
|
||||||
|
|
||||||
Working without setuptools / from source
|
activating a checkout or tarball without setuptools
|
||||||
==========================================
|
-------------------------------------------------------------
|
||||||
|
|
||||||
If you have a checkout_ or a tarball_ it is actually not neccessary to issue
|
To import the py lib the ``py`` package directory needs to
|
||||||
``setup.py`` commands in order to use py lib and its tools. You can
|
be on the ``$PYTHONPATH``. If you exexute scripts directly
|
||||||
simply add the root directory to ``PYTHONPATH`` and ``py/bin`` or
|
from ``py/bin/`` or ``py\bin\win32`` they will find their
|
||||||
``py\bin\win32`` to your ``PATH`` settings.
|
containing py lib automatically.
|
||||||
|
|
||||||
There are also helper scripts to set the environment
|
It is usually a good idea to add the parent directory of the ``py`` package
|
||||||
on windows::
|
directory to your ``PYTHONPATH`` and ``py/bin`` or ``py\bin\win32`` to your
|
||||||
|
system wide ``PATH`` settings. There are helper scripts that set ``PYTHONPATH`` and ``PATH`` on your system:
|
||||||
|
|
||||||
|
on windows execute::
|
||||||
|
|
||||||
|
# inside autoexec.bat or shell startup
|
||||||
c:\\path\to\checkout\py\env.cmd
|
c:\\path\to\checkout\py\env.cmd
|
||||||
|
|
||||||
and on linux/osx you can add something like this to
|
on linux/OSX add this to your shell initialization::
|
||||||
your shell initialization::
|
|
||||||
|
|
||||||
|
# inside .bashrc
|
||||||
eval `python ~/path/to/checkout/py/env.py`
|
eval `python ~/path/to/checkout/py/env.py`
|
||||||
|
|
||||||
both of which which will get you good settings
|
both of which which will get you good settings
|
||||||
for ``PYTHONPATH`` and ``PATH``.
|
for ``PYTHONPATH`` and ``PATH``.
|
||||||
|
|
||||||
Note also that the command line scripts will look
|
|
||||||
|
note: scripts look for "nearby" py-lib
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
Note that the `command line scripts`_ will look
|
||||||
for "nearby" py libs, so if you have a layout like this::
|
for "nearby" py libs, so if you have a layout like this::
|
||||||
|
|
||||||
mypkg/
|
mypkg/
|
||||||
|
@ -90,39 +105,26 @@ for "nearby" py libs, so if you have a layout like this::
|
||||||
tests/
|
tests/
|
||||||
py/
|
py/
|
||||||
|
|
||||||
then issuing ``py.test subpkg1`` will use the py lib
|
issuing ``py.test subpkg1`` will use the py lib
|
||||||
from that projects root directory.
|
from that projects root directory.
|
||||||
|
|
||||||
|
.. _`command line scripts`: bin.html
|
||||||
|
|
||||||
Debian and RPM packages
|
Debian and RPM packages
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
As of July 2009 pytest/pylib 1.0 RPMs and Debian packages
|
As of August 2009 pytest/pylib 1.0 RPMs and Debian packages
|
||||||
are not yet available. So you will only find older
|
are not available. You will only find 0.9 versions -
|
||||||
versions.
|
on Debian systems look for ``python-codespeak-lib``
|
||||||
|
and Dwayne Bailey has put together a Fedora `RPM`_.
|
||||||
|
|
||||||
On Debian systems look for ``python-codespeak-lib``.
|
If you can help with providing/upgrading distribution
|
||||||
*But this package is probably outdated - if somebody
|
packages please use of the contact_ channels in case
|
||||||
can help with bringing this up to date,
|
of questions or need for changes.
|
||||||
that would be very much appreciated.*
|
|
||||||
|
|
||||||
Dwayne Bailey has thankfully put together a Fedora `RPM`_.
|
.. _contact: contact.html
|
||||||
|
|
||||||
.. _`RPM`: http://translate.sourceforge.net/releases/testing/fedora/pylib-0.9.2-1.fc9.noarch.rpm
|
.. _`RPM`: http://translate.sourceforge.net/releases/testing/fedora/pylib-0.9.2-1.fc9.noarch.rpm
|
||||||
|
|
||||||
.. _`setuptools installation`: http://pypi.python.org/pypi/setuptools
|
.. _`setuptools installation`: http://pypi.python.org/pypi/setuptools
|
||||||
|
|
||||||
.. _tarball:
|
|
||||||
|
|
||||||
Installing from a TAR archive
|
|
||||||
===================================================
|
|
||||||
|
|
||||||
You need a working `setuptools installation`_.
|
|
||||||
|
|
||||||
Go to the python package index (pypi) and download a tar file:
|
|
||||||
|
|
||||||
http://pypi.python.org/pypi/py/
|
|
||||||
|
|
||||||
and unpack it to a directory, where you then type::
|
|
||||||
|
|
||||||
python setup.py install
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
==================================
|
||||||
|
Frequently Asked Questions
|
||||||
|
==================================
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
:depth: 2
|
||||||
|
|
||||||
|
On naming, nose and magic
|
||||||
|
============================
|
||||||
|
|
||||||
|
Why the ``py`` naming? what is it?
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Because the name was kind of available and there was the
|
||||||
|
idea to have the package evolve into a "standard" library
|
||||||
|
kind of thing that works cross-python versions and is
|
||||||
|
not tied to a particular CPython revision or its release
|
||||||
|
cycle. Clearly, this was ambitious and the naming
|
||||||
|
has maybe haunted the project rather than helping it.
|
||||||
|
There may be a project name change and possibly a
|
||||||
|
split up into different projects sometime.
|
||||||
|
|
||||||
|
Why the ``py.test`` naming?
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
the py lib contains other command line tools that
|
||||||
|
all share the ``py.`` prefix which makes it easy
|
||||||
|
to use TAB-completion on the shell. Another motivation
|
||||||
|
was to make it obvious where testing functionality
|
||||||
|
for the ``py.test`` command line tool is: in the
|
||||||
|
``py.test`` package name space.
|
||||||
|
|
||||||
|
What's the relation to ``nosetests``?
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
py.test and nose_ share basic philosophy when it comes
|
||||||
|
to running Python tests. In fact,
|
||||||
|
with py.test-1.0.1 it is easy to run many test suites
|
||||||
|
that currently work with ``nosetests``. nose_ was created
|
||||||
|
as a clone of ``py.test`` when it was in the ``0.8`` release
|
||||||
|
cycle so some of the newer features_ introduced with py.test-1.0
|
||||||
|
have no counterpart in nose_.
|
||||||
|
|
||||||
|
.. _nose: http://somethingaboutorange.com/mrl/projects/nose/0.11.1/
|
||||||
|
.. _features: test/features.html
|
||||||
|
|
||||||
|
What's all this "magic" with py.test?
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
"All this magic" usually boils down to two issues:
|
||||||
|
|
||||||
|
* There is a special tweak to importing: `py/__init__.py`_ contains
|
||||||
|
a dictionary which maps the importable ``py.*`` namespaces to
|
||||||
|
objects in files. When looking at the project source code
|
||||||
|
you see imports like ``from py.__.test.session import Session``. The
|
||||||
|
the double ``__`` underscore indicates the "normal" python
|
||||||
|
filesystem/namespace coupled import, i.e. it points to
|
||||||
|
``py/test/session.py``'s ``Session`` object. However,
|
||||||
|
from the outside you use the "non-underscore" `py namespaces`_
|
||||||
|
so this distinction usually only shows up if you hack
|
||||||
|
on internal code or see internal tracebacks.
|
||||||
|
|
||||||
|
* when an ``assert`` fails, py.test re-interprets the expression
|
||||||
|
to show intermediate values. This allows to use the plain ``assert``
|
||||||
|
statement instead of the many methods that you otherwise need
|
||||||
|
to mimick this behaviour. This means that in case of a failing
|
||||||
|
assert, your expressions gets evaluated *twice*. If your expression
|
||||||
|
has side effects the outcome may be different. If the test suddenly
|
||||||
|
passes you will get a detailed message. It is good practise, anyway,
|
||||||
|
to not have asserts with side effects. ``py.test --nomagic`` turns
|
||||||
|
off assert re-intepretation.
|
||||||
|
|
||||||
|
Other than that, ``py.test`` has bugs or quirks like any other computer
|
||||||
|
software. In fact, it has a *strong* focus on running robustly and has
|
||||||
|
over a thousand automated tests for its own code base.
|
||||||
|
|
||||||
|
.. _`py namespaces`: index.html
|
||||||
|
.. _`py/__init__.py`: http://bitbucket.org/hpk42/py-trunk/src/1.0.x/py/__init__.py
|
||||||
|
|
||||||
|
|
||||||
|
function arguments and parametrized tests
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
.. _`why pytest_pyfuncarg__ methods?`:
|
||||||
|
|
||||||
|
Why the ``pytest_funcarg__*`` name for funcarg factories?
|
||||||
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
When experimenting with funcargs an explicit registration mechanism
|
||||||
|
was considered. But lacking a good use case for this indirection and
|
||||||
|
flexibility we decided to go for `Convention over Configuration`_ and
|
||||||
|
allow to directly specify the factory. Besides removing the need
|
||||||
|
for an indirection it allows to "grep" for ``pytest_funcarg__MYARG``
|
||||||
|
and will safely find all factory functions for the ``MYARG`` function
|
||||||
|
argument. It helps to alleviates the de-coupling of function
|
||||||
|
argument usage and creation.
|
||||||
|
|
||||||
|
.. _`Convention over Configuration`: http://en.wikipedia.org/wiki/Convention_over_Configuration
|
||||||
|
|
||||||
|
Can i yield multiple values from a factory function?
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
There are two reasons why yielding from a factory function
|
||||||
|
is not possible:
|
||||||
|
|
||||||
|
* Calling factories for obtaining test function arguments
|
||||||
|
is part of setting up and running a test. At that
|
||||||
|
point it is not possible to add new test calls to
|
||||||
|
the test collection anymore.
|
||||||
|
|
||||||
|
* If multiple factories yielded values there would
|
||||||
|
be no natural place to determine the combination
|
||||||
|
policy - in real-world examples some combinations
|
||||||
|
often should not run.
|
||||||
|
|
||||||
|
Use the `pytest_generate_tests`_ hook to solve both issues
|
||||||
|
and implement the `parametrization scheme of your choice`_.
|
||||||
|
|
||||||
|
.. _`pytest_generate_tests`: test/funcargs.html#parametrizing-tests
|
||||||
|
.. _`parametrization scheme of your choice`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ For the latest Release, see `PyPI project page`_
|
||||||
.. _`py.io`: io.html
|
.. _`py.io`: io.html
|
||||||
.. _`py.path`: path.html
|
.. _`py.path`: path.html
|
||||||
.. _`py.code`: code.html
|
.. _`py.code`: code.html
|
||||||
.. _`py.test`: test/test.html
|
.. _`py.test`: test/index.html
|
||||||
.. _`py lib scripts`: bin.html
|
.. _`py lib scripts`: bin.html
|
||||||
.. _`py.xml`: xml.html
|
.. _`py.xml`: xml.html
|
||||||
.. _`miscellaneous features`: misc.html
|
.. _`miscellaneous features`: misc.html
|
||||||
|
|
|
@ -72,3 +72,46 @@ Customizing execution of Items and Functions
|
||||||
.. _`py-dev mailing list`: http://codespeak.net/mailman/listinfo/py-dev
|
.. _`py-dev mailing list`: http://codespeak.net/mailman/listinfo/py-dev
|
||||||
|
|
||||||
|
|
||||||
|
.. _`test generators`: funcargs.html#test-generators
|
||||||
|
|
||||||
|
.. _`generative tests`:
|
||||||
|
|
||||||
|
generative tests: yielding parametrized tests
|
||||||
|
====================================================
|
||||||
|
|
||||||
|
Deprecated since 1.0 in favour of `test generators`_.
|
||||||
|
|
||||||
|
*Generative tests* are test methods that are *generator functions* which
|
||||||
|
``yield`` callables and their arguments. This is useful for running a
|
||||||
|
test function multiple times against different parameters. Example::
|
||||||
|
|
||||||
|
def test_generative():
|
||||||
|
for x in (42,17,49):
|
||||||
|
yield check, x
|
||||||
|
|
||||||
|
def check(arg):
|
||||||
|
assert arg % 7 == 0 # second generated tests fails!
|
||||||
|
|
||||||
|
Note that ``test_generative()`` will cause three tests
|
||||||
|
to get run, notably ``check(42)``, ``check(17)`` and ``check(49)``
|
||||||
|
of which the middle one will obviously fail.
|
||||||
|
|
||||||
|
To make it easier to distinguish the generated tests it is possible to specify an explicit name for them, like for example::
|
||||||
|
|
||||||
|
def test_generative():
|
||||||
|
for x in (42,17,49):
|
||||||
|
yield "case %d" % x, check, x
|
||||||
|
|
||||||
|
|
||||||
|
disabling a test class
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
If you want to disable a complete test class you
|
||||||
|
can set the class-level attribute ``disabled``.
|
||||||
|
For example, in order to avoid running some tests on Win32::
|
||||||
|
|
||||||
|
class TestPosixOnly:
|
||||||
|
disabled = sys.platform == 'win32'
|
||||||
|
|
||||||
|
def test_xxx(self):
|
||||||
|
...
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="refresh" content=" 1 ; URL=customize.html" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||||
|
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var pageTracker = _gat._getTracker("UA-7597274-3");
|
||||||
|
pageTracker._trackPageview();
|
||||||
|
} catch(err) {}</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
.. contents::
|
|
||||||
:local:
|
|
||||||
:depth: 2
|
|
||||||
|
|
||||||
available test options
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
You can see command line options by running::
|
|
||||||
|
|
||||||
py.test -h
|
|
||||||
|
|
||||||
This will display all available command line options
|
|
||||||
including the ones added by plugins `loaded at tool startup`_.
|
|
||||||
|
|
||||||
.. _`loaded at tool startup`: extend.html#tool-startup
|
|
||||||
|
|
||||||
.. _conftestpy:
|
|
||||||
.. _collectignore:
|
|
||||||
|
|
||||||
conftest.py: project specific test configuration
|
|
||||||
--------------------------------------------------------
|
|
||||||
|
|
||||||
A unique feature of py.test are its powerful ``conftest.py`` files which
|
|
||||||
allow to `set option defaults`_, `implement hooks`_, `specify funcargs`_
|
|
||||||
or set particular variables to influence the testing process:
|
|
||||||
|
|
||||||
* ``pytest_plugins``: list of named plugins to load
|
|
||||||
|
|
||||||
* ``collect_ignore``: list of paths to ignore during test collection (relative to the containing
|
|
||||||
``conftest.py`` file)
|
|
||||||
|
|
||||||
* ``rsyncdirs``: list of to-be-rsynced directories for distributed
|
|
||||||
testing
|
|
||||||
|
|
||||||
You may put a conftest.py files in your project root directory or into
|
|
||||||
your package directory if you want to add project-specific test options.
|
|
||||||
|
|
||||||
``py.test`` loads all ``conftest.py`` files upwards from the command
|
|
||||||
line specified test files. It will lookup configuration values
|
|
||||||
right-to-left, i.e. the closer conftest files will be checked first.
|
|
||||||
You may have a ``conftest.py`` in your very home directory to have some
|
|
||||||
global configuration values.
|
|
||||||
|
|
||||||
There is a flag that may help you debugging your conftest.py
|
|
||||||
configuration::
|
|
||||||
|
|
||||||
py.test --traceconfig
|
|
||||||
|
|
||||||
.. _`implement hooks`: extend.html#conftest.py-plugin
|
|
||||||
.. _`specify funcargs`: funcargs.html#application-setup-tutorial-example
|
|
||||||
|
|
||||||
.. _`set option defaults`:
|
|
||||||
|
|
||||||
setting option defaults
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
py.test will lookup values of options in this order:
|
|
||||||
|
|
||||||
* option value supplied at command line
|
|
||||||
* content of environment variable ``PYTEST_OPTION_NAME=...``
|
|
||||||
* ``name = ...`` setting in the nearest ``conftest.py`` file.
|
|
||||||
|
|
||||||
The name of an option usually is the one you find
|
|
||||||
in the longform of the option, i.e. the name
|
|
||||||
behind the ``--`` double-dash that you get with ``py.test -h``.
|
|
||||||
|
|
||||||
IOW, you can set default values for options per project, per
|
|
||||||
home-directoray, per shell session or per test-run.
|
|
||||||
|
|
||||||
.. _`basetemp`:
|
|
||||||
|
|
||||||
Temporary directories
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
``py.test`` runs provide means to create per-test session
|
|
||||||
temporary (sub) directories through the config object.
|
|
||||||
You can create directories by calling a method
|
|
||||||
on the config object:
|
|
||||||
|
|
||||||
- ``config.mktemp(basename)``: create and returns a new tempdir
|
|
||||||
|
|
||||||
- ``config.ensuretemp(basename)``: create or return a new tempdir
|
|
||||||
|
|
||||||
tempdirs are created as sub directories of a per-session testdir
|
|
||||||
and will keep around the directories of the last three
|
|
||||||
test runs. You can also set the base temporary directory
|
|
||||||
with the `--basetemp`` option. When distributing
|
|
||||||
tests on the same machine, ``py.test`` takes care to
|
|
||||||
pass around the basetemp directory such that all temporary
|
|
||||||
files land below the same basetemp directory.
|
|
||||||
|
|
||||||
The config object is available when implementing `function arguments`_
|
|
||||||
or `extensions`_ and can otherwise be globally accessed as ``py.test.config``.
|
|
||||||
|
|
||||||
.. _`function arguments`: funcargs.html
|
|
||||||
.. _`extensions`: extend.html
|
|
|
@ -1,9 +1,108 @@
|
||||||
================================================
|
================================================
|
||||||
Extending and customizing py.test
|
Customizing and Extending py.test
|
||||||
================================================
|
================================================
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
:depth: 2
|
||||||
|
|
||||||
|
basic test configuration
|
||||||
|
===================================
|
||||||
|
|
||||||
|
available command line options
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
You can see command line options by running::
|
||||||
|
|
||||||
|
py.test -h
|
||||||
|
|
||||||
|
This will display all available command line options
|
||||||
|
in your specific environment.
|
||||||
|
|
||||||
|
.. _`project-specific test configuration`:
|
||||||
|
.. _`collect_ignore`:
|
||||||
|
|
||||||
|
conftest.py: project specific hooks and configuration
|
||||||
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
A unique feature of py.test are its ``conftest.py`` files which
|
||||||
|
allow to:
|
||||||
|
|
||||||
|
* `set option defaults`_
|
||||||
|
|
||||||
|
* `implement hooks`_
|
||||||
|
|
||||||
|
* `specify funcargs`_
|
||||||
|
|
||||||
|
or set particular variables to influence the testing process:
|
||||||
|
|
||||||
|
* ``pytest_plugins``: list of named plugins to load
|
||||||
|
|
||||||
|
* ``collect_ignore``: list of paths to ignore during test collection, relative to the containing ``conftest.py`` file
|
||||||
|
|
||||||
|
* ``rsyncdirs``: list of to-be-rsynced directories for distributed
|
||||||
|
testing, relative to the containing ``conftest.py`` file.
|
||||||
|
|
||||||
|
You may put a conftest.py files in your project root directory or into
|
||||||
|
your package directory if you want to add project-specific test options.
|
||||||
|
|
||||||
|
``py.test`` loads all ``conftest.py`` files upwards from the command
|
||||||
|
line file arguments. It usually looks up configuration values
|
||||||
|
right-to-left, i.e. the closer conftest files will be checked first.
|
||||||
|
This means you can have a ``conftest.py`` in your very home directory to
|
||||||
|
have some global configuration values.
|
||||||
|
|
||||||
|
.. _`specify funcargs`: funcargs.html#application-setup-tutorial-example
|
||||||
|
|
||||||
|
.. _`set option defaults`:
|
||||||
|
|
||||||
|
setting persistent option defaults
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
py.test will lookup option values in this order:
|
||||||
|
|
||||||
|
* command line
|
||||||
|
* conftest.py files
|
||||||
|
* environment variables
|
||||||
|
|
||||||
|
To find out about the particular switches and type::
|
||||||
|
|
||||||
|
py.test --help-config
|
||||||
|
|
||||||
|
This will print information about all options in your
|
||||||
|
environment, including your local plugins.
|
||||||
|
|
||||||
|
.. _`basetemp`:
|
||||||
|
|
||||||
|
Temporary directories
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
You can create directories by calling one of two methods
|
||||||
|
on the config object:
|
||||||
|
|
||||||
|
- ``config.mktemp(basename)``: create and return a new tempdir
|
||||||
|
|
||||||
|
- ``config.ensuretemp(basename)``: create or return a new tempdir
|
||||||
|
|
||||||
|
temporary directories are created as sub directories of a per-session
|
||||||
|
testdir and will keep around the directories of the last three test
|
||||||
|
runs. You can set the base temporary directory through the command line
|
||||||
|
`--basetemp`` option. When distributing tests on the same machine,
|
||||||
|
``py.test`` takes care to configure a basetemp directory for the sub
|
||||||
|
processes such that all temporary data lands below below a single
|
||||||
|
per-test run basetemp directory.
|
||||||
|
|
||||||
|
.. _`function arguments`: funcargs.html
|
||||||
|
.. _`extensions`:
|
||||||
|
|
||||||
|
Plugin basics
|
||||||
|
=========================
|
||||||
|
|
||||||
.. _`local plugin`:
|
.. _`local plugin`:
|
||||||
|
|
||||||
|
project specific "local" or named "global" plugins
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
py.test implements much of its functionality by calling `well specified
|
py.test implements much of its functionality by calling `well specified
|
||||||
hooks`_. Python modules which contain such hook functions are called
|
hooks`_. Python modules which contain such hook functions are called
|
||||||
plugins. Hook functions are discovered in ``conftest.py`` files or in
|
plugins. Hook functions are discovered in ``conftest.py`` files or in
|
||||||
|
@ -18,6 +117,7 @@ named plugins must be explicitely specified.
|
||||||
.. _`named plugins`: plugin/index.html
|
.. _`named plugins`: plugin/index.html
|
||||||
|
|
||||||
.. _`tool startup`:
|
.. _`tool startup`:
|
||||||
|
.. _`loaded at tool startup`:
|
||||||
.. _`test tool starts up`:
|
.. _`test tool starts up`:
|
||||||
|
|
||||||
Plugin discovery at tool startup
|
Plugin discovery at tool startup
|
||||||
|
@ -81,17 +181,18 @@ by defining the following hook in a ``conftest.py`` file:
|
||||||
if config.getvalue("runall"):
|
if config.getvalue("runall"):
|
||||||
collect_ignore[:] = []
|
collect_ignore[:] = []
|
||||||
|
|
||||||
.. _`project-specific test configuration`: config.html#conftestpy
|
|
||||||
.. _`collect_ignore`: config.html#collectignore
|
|
||||||
|
|
||||||
.. _`well specified hooks`:
|
.. _`well specified hooks`:
|
||||||
|
.. _`implement hooks`:
|
||||||
|
|
||||||
Available py.test hooks
|
Important py.test hooks
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
py.test calls hooks functions to implement its `test collection`_, running and
|
py.test calls hooks functions to implement its `test collection`_,
|
||||||
reporting process. When py.test loads a plugin it validates that all hook functions
|
running and reporting process. When py.test loads a plugin it validates
|
||||||
conform to the `hook definition specification`_. The hook function name and its
|
that all hook functions conform to the `hook definition specification`_.
|
||||||
|
|
||||||
|
The hook function name and its
|
||||||
argument names need to match exactly but it is allowed for an implementation
|
argument names need to match exactly but it is allowed for an implementation
|
||||||
to accept *less* parameters. You'll get useful errors on mistyped hook or
|
to accept *less* parameters. You'll get useful errors on mistyped hook or
|
||||||
argument names. Read on for some introductory information on particular
|
argument names. Read on for some introductory information on particular
|
||||||
|
@ -170,9 +271,10 @@ For example, the `pytest_pdb plugin`_ uses this hook to activate
|
||||||
interactive debugging on failures when ``--pdb`` is specified on the
|
interactive debugging on failures when ``--pdb`` is specified on the
|
||||||
command line.
|
command line.
|
||||||
|
|
||||||
Usually three reports will be generated for a single test item. However,
|
Usually three reports will be generated for a single test item for each
|
||||||
if the ``pytest_runtest_setup`` fails no call or teardown hooks
|
of the three runtest hooks respectively. If ``pytest_runtest_setup``
|
||||||
will be called and only one report will be created.
|
fails then ``pytest_runtest_teardown`` will be called but not
|
||||||
|
``pytest_runtest_call``.
|
||||||
|
|
||||||
Each of the up to three reports is eventually fed to the logreport hook:
|
Each of the up to three reports is eventually fed to the logreport hook:
|
||||||
|
|
||||||
|
@ -194,7 +296,7 @@ A ``report`` object contains status and reporting information:
|
||||||
The `pytest_terminal plugin`_ uses this hook to print information
|
The `pytest_terminal plugin`_ uses this hook to print information
|
||||||
about a test run.
|
about a test run.
|
||||||
|
|
||||||
The protocol described here is implemented via this hook:
|
The whole protocol described here is implemented via this hook:
|
||||||
|
|
||||||
.. sourcecode:: python
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
@ -251,19 +353,6 @@ Python module. The return value is a custom `collection node`_ or None.
|
||||||
.. XXX or ``False`` if you want to indicate that the given item should not be collected.
|
.. XXX or ``False`` if you want to indicate that the given item should not be collected.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Included default plugins
|
|
||||||
=============================
|
|
||||||
|
|
||||||
You can find the source code of all default plugins in
|
|
||||||
|
|
||||||
http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/
|
|
||||||
|
|
||||||
Additionally you can check out some more contributed plugins here
|
|
||||||
|
|
||||||
http://bitbucket.org/hpk42/py-trunk/src/tip/contrib/
|
|
||||||
|
|
||||||
|
|
||||||
.. _`collection process`:
|
.. _`collection process`:
|
||||||
.. _`collection node`:
|
.. _`collection node`:
|
||||||
.. _`test collection`:
|
.. _`test collection`:
|
||||||
|
@ -272,6 +361,9 @@ Additionally you can check out some more contributed plugins here
|
||||||
Test Collection process
|
Test Collection process
|
||||||
======================================================
|
======================================================
|
||||||
|
|
||||||
|
the collection tree
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
The collecting process is iterative so that distribution
|
The collecting process is iterative so that distribution
|
||||||
and execution of tests can start as soon as the first test
|
and execution of tests can start as soon as the first test
|
||||||
item is collected. Collection nodes with children are
|
item is collected. Collection nodes with children are
|
|
@ -0,0 +1,18 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="refresh" content=" 1 ; URL=customize.html" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||||
|
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var pageTracker = _gat._getTracker("UA-7597274-3");
|
||||||
|
pageTracker._trackPageview();
|
||||||
|
} catch(err) {}</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -1,117 +1,77 @@
|
||||||
==================================================
|
==================================================
|
||||||
py.test features
|
py.test feature overview
|
||||||
==================================================
|
==================================================
|
||||||
|
|
||||||
py.test is an extensible tool for running all kinds
|
.. contents::
|
||||||
of tests on one or more machines. It supports a variety
|
:local:
|
||||||
of testing methods including unit, functional, integration
|
|
||||||
and doc-testing. It is used in projects that run more
|
|
||||||
than 10 thousand tests regularly as well as in single-file projects.
|
|
||||||
|
|
||||||
py.test presents a clean and powerful command line interface
|
|
||||||
and strives to generally make testing a fun no-boilerplate effort.
|
|
||||||
It works and is tested against linux, windows and osx
|
|
||||||
on CPython 2.3 - CPython 2.6.
|
|
||||||
|
|
||||||
.. contents:: List of Contents
|
|
||||||
:depth: 1
|
:depth: 1
|
||||||
|
|
||||||
|
mature command line testing tool
|
||||||
|
====================================================
|
||||||
|
|
||||||
|
py.test is a command line tool to collect and run automated tests. It
|
||||||
|
runs well on Linux, Windows and OSX Python 2.4 through to 2.6 versions.
|
||||||
|
It can distribute a single test run to multiple machines. It is used in
|
||||||
|
many projects, ranging from running 10 thousands of tests integrated
|
||||||
|
with buildbot to a few inlined tests on a command line script.
|
||||||
|
|
||||||
.. _`autocollect`:
|
.. _`autocollect`:
|
||||||
|
|
||||||
automatically collects and executes tests
|
automatically collects and executes tests
|
||||||
===============================================
|
===============================================
|
||||||
|
|
||||||
py.test discovers tests automatically by inspecting specified
|
py.test discovers tests automatically by looking at
|
||||||
directories or files. By default, it collects all python
|
specified directories and its files for common
|
||||||
modules a leading ``test_`` or trailing ``_test`` filename.
|
naming patterns. As ``py.test`` operates as a separate
|
||||||
From each test module every function with a leading ``test_``
|
cmdline tool you can easily have a command line utility and
|
||||||
or class with a leading ``Test`` name is collected.
|
|
||||||
|
|
||||||
.. _`collection process`: extend.html#collection-process
|
|
||||||
|
|
||||||
|
|
||||||
funcargs and xUnit style setups
|
|
||||||
===================================================
|
|
||||||
|
|
||||||
py.test provides powerful means for managing test
|
|
||||||
state and fixtures. Apart from the `traditional
|
|
||||||
xUnit style setup`_ for unittests it features the
|
|
||||||
simple and powerful `funcargs mechanism`_ for handling
|
|
||||||
both complex and simple test scenarious.
|
|
||||||
|
|
||||||
.. _`funcargs mechanism`: funcargs.html
|
|
||||||
.. _`traditional xUnit style setup`: xunit_setup.html
|
|
||||||
|
|
||||||
load-balance tests to multiple CPUs
|
|
||||||
===================================
|
|
||||||
|
|
||||||
For large test suites you can distribute your
|
|
||||||
tests to multiple CPUs by issuing for example::
|
|
||||||
|
|
||||||
py.test -n 3
|
|
||||||
|
|
||||||
Read more on `distributed testing`_.
|
|
||||||
|
|
||||||
.. _`distributed testing`: dist.html
|
|
||||||
|
|
||||||
Distribute tests across machines
|
|
||||||
===================================
|
|
||||||
|
|
||||||
py.test supports the sending of tests to
|
|
||||||
remote ssh-accounts or socket servers.
|
|
||||||
It can `ad-hoc run your test on multiple
|
|
||||||
platforms one a single test run`. Ad-hoc
|
|
||||||
means that there are **no installation
|
|
||||||
requirements whatsoever** on the remote side.
|
|
||||||
|
|
||||||
.. _`ad-hoc run your test on multiple platforms one a single test run`: dist.html#atonce
|
|
||||||
|
|
||||||
extensive debugging support
|
|
||||||
===================================
|
|
||||||
|
|
||||||
testing starts immediately
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Testing starts as soon as the first ``test item``
|
|
||||||
is collected. The collection process is iterative
|
|
||||||
and does not need to complete before your first
|
|
||||||
test items are executed.
|
|
||||||
|
|
||||||
support for modules containing tests
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
As ``py.test`` operates as a separate cmdline
|
|
||||||
tool you can easily have a command line utility and
|
|
||||||
some tests in the same file.
|
some tests in the same file.
|
||||||
|
|
||||||
debug with the ``print`` statement
|
supports many testing practises and methods
|
||||||
----------------------------------
|
==================================================================
|
||||||
|
|
||||||
By default, ``py.test`` catches text written to stdout/stderr during
|
py.test supports many testing methods conventionally used in
|
||||||
the execution of each individual test. This output will only be
|
the Python community. It runs traditional `unittest.py`_,
|
||||||
displayed however if the test fails; you will not see it
|
`doctest.py`_, supports `xUnit style setup`_ and nose_ specific
|
||||||
otherwise. This allows you to put debugging print statements in your
|
setups and test suites. It offers minimal no-boilerplate model
|
||||||
code without being overwhelmed by all the output that might be
|
for configuring and deploying tests written as simple Python
|
||||||
generated by tests that do not fail.
|
functions or methods. It also integrates `coverage testing
|
||||||
|
with figleaf`_ or `Javasript unit- and functional testing`_.
|
||||||
|
|
||||||
Each failing test that produced output during the running of the test
|
.. _`Javasript unit- and functional testing`: plugin/oejskit.html
|
||||||
function will have its output displayed in the ``recorded stdout`` section.
|
.. _`coverage testing with figleaf`: plugin/figleaf.html
|
||||||
|
|
||||||
During Setup and Teardown ("Fixture") capturing is performed separately so
|
no-boilerplate test functions with Python
|
||||||
that you will only see this output if the actual fixture functions fail.
|
===================================================
|
||||||
|
|
||||||
The catching of stdout/stderr output can be disabled using the
|
automatic Python test discovery
|
||||||
``--nocapture`` or ``-s`` option to the ``py.test`` tool. Any output will
|
------------------------------------
|
||||||
in this case be displayed as soon as it is generated.
|
|
||||||
|
|
||||||
test execution order
|
By default, all python modules with a ``test_*.py``
|
||||||
--------------------------------
|
filename are inspected for finding tests:
|
||||||
|
|
||||||
Tests usually run in the order in which they appear in the files.
|
* functions with a name beginning with ``test_``
|
||||||
However, tests should not rely on running one after another, as
|
* classes with a leading ``Test`` name and ``test`` prefixed methods.
|
||||||
this prevents more advanced usages: running tests
|
* ``unittest.TestCase`` subclasses
|
||||||
distributedly or selectively, or in "looponfailing" mode,
|
|
||||||
will cause them to run in random order.
|
test functions can run with different argument sets
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
py.test offers the unique `funcargs mechanism`_ for setting up
|
||||||
|
and passing project-specific objects to Python test functions.
|
||||||
|
Test Parametrization happens by triggering a call to the same test
|
||||||
|
functions with different argument values.
|
||||||
|
|
||||||
|
per-test capturing of output, including subprocesses
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
By default, ``py.test`` captures all writes to stdout/stderr.
|
||||||
|
Output from ``print`` statements as well as from subprocesses
|
||||||
|
is captured_. When a test fails, the associated captured outputs are shown.
|
||||||
|
This allows you to put debugging print statements in your code without
|
||||||
|
being overwhelmed by all the output that might be generated by tests
|
||||||
|
that do not fail.
|
||||||
|
|
||||||
|
.. _captured: plugin/capture.html
|
||||||
|
|
||||||
assert with the ``assert`` statement
|
assert with the ``assert`` statement
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
@ -142,61 +102,35 @@ one of two forms::
|
||||||
py.test.raises(Exception, func, *args, **kwargs)
|
py.test.raises(Exception, func, *args, **kwargs)
|
||||||
py.test.raises(Exception, "func(*args, **kwargs)")
|
py.test.raises(Exception, "func(*args, **kwargs)")
|
||||||
|
|
||||||
both of which execute the given function with args and kwargs and
|
both of which execute the specified function with args and kwargs and
|
||||||
asserts that the given ``Exception`` is raised. The reporter will
|
asserts that the given ``Exception`` is raised. The reporter will
|
||||||
provide you with helpful output in case of failures such as *no
|
provide you with helpful output in case of failures such as *no
|
||||||
exception* or *wrong exception*.
|
exception* or *wrong exception*.
|
||||||
|
|
||||||
useful tracebacks, recursion detection
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
A lot of care is taken to present nice tracebacks in case of test
|
information-rich tracebacks, PDB introspection
|
||||||
failure. Try::
|
-------------------------------------------------------
|
||||||
|
|
||||||
py.test py/doc/example/pytest/failure_demo.py
|
.. _`example tracebacks`: http://paste.pocoo.org/show/134814/
|
||||||
|
|
||||||
to see a variety of tracebacks, each representing a different
|
A lot of care is taken to present useful failure information
|
||||||
failure situation.
|
and in particular nice and concise Python tracebacks. This
|
||||||
|
is especially useful if you need to regularly look at failures
|
||||||
|
from nightly runs, i.e. are detached from the actual test
|
||||||
|
running session. Here are `example tracebacks`_ for a number of failing
|
||||||
|
test functions. You can modify traceback printing styles through the
|
||||||
|
command line. Using the `--pdb`` option you can automatically activate
|
||||||
|
a PDB `Python debugger`_ when a test fails.
|
||||||
|
|
||||||
``py.test`` uses the same order for presenting tracebacks as Python
|
advanced skipping of tests
|
||||||
itself: the oldest function call is shown first, and the most recent call is
|
|
||||||
shown last. A ``py.test`` reported traceback starts with your
|
|
||||||
failing test function. If the maximum recursion depth has been
|
|
||||||
exceeded during the running of a test, for instance because of
|
|
||||||
infinite recursion, ``py.test`` will indicate where in the
|
|
||||||
code the recursion was taking place. You can inhibit
|
|
||||||
traceback "cutting" magic by supplying ``--fulltrace``.
|
|
||||||
|
|
||||||
There is also the possibility of using ``--tb=short`` to get regular CPython
|
|
||||||
tracebacks. Or you can use ``--tb=no`` to not show any tracebacks at all.
|
|
||||||
|
|
||||||
no inheritance requirement
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Test classes are recognized by their leading ``Test`` name. Unlike
|
|
||||||
``unitest.py``, you don't need to inherit from some base class to make
|
|
||||||
them be found by the test runner. Besides being easier, it also allows
|
|
||||||
you to write test classes that subclass from application level
|
|
||||||
classes.
|
|
||||||
|
|
||||||
testing for deprecated APIs
|
|
||||||
------------------------------
|
|
||||||
|
|
||||||
In your tests you can use ``py.test.deprecated_call(func, *args, **kwargs)``
|
|
||||||
to test that a particular function call triggers a DeprecationWarning.
|
|
||||||
This is useful for testing phasing out of old APIs in your projects.
|
|
||||||
|
|
||||||
|
|
||||||
advanced test selection / skipping
|
|
||||||
=========================================================
|
|
||||||
|
|
||||||
dynamically 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. Example::
|
test or setup functions. Example::
|
||||||
|
|
||||||
py.test.skip("message")
|
def test_hello():
|
||||||
|
if sys.platform != "win32":
|
||||||
|
py.test.skip("only win32 supported")
|
||||||
|
|
||||||
You can also use a helper to skip on a failing import::
|
You can also use a helper to skip on a failing import::
|
||||||
|
|
||||||
|
@ -206,15 +140,48 @@ or to skip if a library does not have the right version::
|
||||||
|
|
||||||
docutils = py.test.importorskip("docutils", minversion="0.3")
|
docutils = py.test.importorskip("docutils", minversion="0.3")
|
||||||
|
|
||||||
The version will be read from the module's ``__version__`` attribute.
|
The version will be read from the specified module's ``__version__`` attribute.
|
||||||
|
|
||||||
|
.. _`funcargs mechanism`: funcargs.html
|
||||||
|
.. _`unittest.py`: http://docs.python.org/library/unittest.html
|
||||||
|
.. _`doctest.py`: http://docs.python.org/library/doctest.html
|
||||||
|
.. _`xUnit style setup`: xunit_setup.html
|
||||||
|
.. _`pytest_nose`: plugin/nose.html
|
||||||
|
|
||||||
|
load-balance test runs to multiple CPUs
|
||||||
|
========================================
|
||||||
|
|
||||||
|
For large test suites you can distribute your
|
||||||
|
tests to multiple CPUs by issuing for example::
|
||||||
|
|
||||||
|
py.test -n 3
|
||||||
|
|
||||||
|
Read more on `distributed testing`_.
|
||||||
|
|
||||||
|
.. _`distributed testing`: dist.html
|
||||||
|
|
||||||
|
ad-hoc run tests cross-platform
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
py.test supports the sending of tests to
|
||||||
|
remote ssh-accounts, socket servers.
|
||||||
|
It can `ad-hoc run your test on multiple
|
||||||
|
platforms one a single test run`. Ad-hoc
|
||||||
|
means that there are **no installation
|
||||||
|
requirements whatsoever** on the remote side.
|
||||||
|
|
||||||
|
.. _`ad-hoc run your test on multiple platforms one a single test run`: dist.html#atonce
|
||||||
|
|
||||||
|
advanced test selection and running modes
|
||||||
|
=========================================================
|
||||||
|
|
||||||
.. _`selection by keyword`:
|
.. _`selection by keyword`:
|
||||||
|
|
||||||
selecting/unselecting tests by keyword
|
``py.test --looponfailing`` allows to run a test suite,
|
||||||
---------------------------------------------
|
memorize all failures and then loop over the failing set
|
||||||
|
of tests until they all pass. It will re-start running
|
||||||
|
the tests when it detects file changes in your project.
|
||||||
|
|
||||||
Pytest's keyword mechanism provides a powerful way to
|
|
||||||
group and selectively run tests in your test code base.
|
|
||||||
You can selectively run tests by specifiying a keyword
|
You can selectively run tests by specifiying a keyword
|
||||||
on the command line. Examples::
|
on the command line. Examples::
|
||||||
|
|
||||||
|
@ -246,65 +213,21 @@ plugin for more information.
|
||||||
|
|
||||||
.. _`pytest_keyword`: plugin/keyword.html
|
.. _`pytest_keyword`: plugin/keyword.html
|
||||||
|
|
||||||
|
|
||||||
disabling a test class
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
If you want to disable a complete test class you
|
|
||||||
can set the class-level attribute ``disabled``.
|
|
||||||
For example, in order to avoid running some tests on Win32::
|
|
||||||
|
|
||||||
class TestPosixOnly:
|
|
||||||
disabled = sys.platform == 'win32'
|
|
||||||
|
|
||||||
def test_xxx(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
.. _`test generators`: funcargs.html#test-generators
|
|
||||||
|
|
||||||
.. _`generative tests`:
|
|
||||||
|
|
||||||
generative tests: yielding parametrized tests
|
|
||||||
====================================================
|
|
||||||
|
|
||||||
Deprecated since 1.0 in favour of `test generators`_.
|
|
||||||
|
|
||||||
*Generative tests* are test methods that are *generator functions* which
|
|
||||||
``yield`` callables and their arguments. This is useful for running a
|
|
||||||
test function multiple times against different parameters. Example::
|
|
||||||
|
|
||||||
def test_generative():
|
|
||||||
for x in (42,17,49):
|
|
||||||
yield check, x
|
|
||||||
|
|
||||||
def check(arg):
|
|
||||||
assert arg % 7 == 0 # second generated tests fails!
|
|
||||||
|
|
||||||
Note that ``test_generative()`` will cause three tests
|
|
||||||
to get run, notably ``check(42)``, ``check(17)`` and ``check(49)``
|
|
||||||
of which the middle one will obviously fail.
|
|
||||||
|
|
||||||
To make it easier to distinguish the generated tests it is possible to specify an explicit name for them, like for example::
|
|
||||||
|
|
||||||
def test_generative():
|
|
||||||
for x in (42,17,49):
|
|
||||||
yield "case %d" % x, check, x
|
|
||||||
|
|
||||||
easy to extend
|
easy to extend
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
Since 1.0 py.test has advanced `extension mechanisms`_
|
py.test has advanced `extension mechanisms`_
|
||||||
and a growing `list of plugins`_.
|
with a growing `list of default plugins`_.
|
||||||
One can can easily modify or add aspects for for
|
One can can easily modify or add aspects for for
|
||||||
purposes such as:
|
purposes such as:
|
||||||
|
|
||||||
* reporting extensions
|
* reporting extensions
|
||||||
* customizing collection and execution of tests
|
* customizing collection and execution of tests
|
||||||
* running non-python tests
|
* running and managing non-python tests
|
||||||
* managing custom test state setup
|
* managing domain-specific test state setup
|
||||||
|
|
||||||
.. _`list of plugins`: plugin/index.html
|
.. _`list of default plugins`: plugin/index.html
|
||||||
.. _`extension mechanisms`: extend.html
|
.. _`extension mechanisms`: customize.html#extensions
|
||||||
|
|
||||||
.. _`reStructured Text`: http://docutils.sourceforge.net
|
.. _`reStructured Text`: http://docutils.sourceforge.net
|
||||||
.. _`Python debugger`: http://docs.python.org/lib/module-pdb.html
|
.. _`Python debugger`: http://docs.python.org/lib/module-pdb.html
|
||||||
|
|
|
@ -2,8 +2,15 @@
|
||||||
**funcargs**: test function arguments FTW
|
**funcargs**: test function arguments FTW
|
||||||
==========================================================
|
==========================================================
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
:depth: 2
|
||||||
|
|
||||||
|
Goals of the "funcarg" mechanism
|
||||||
|
==========================================
|
||||||
|
|
||||||
Since version 1.0 py.test features the "funcarg" mechanism which
|
Since version 1.0 py.test features the "funcarg" mechanism which
|
||||||
allows a test function to take arguments independently provided
|
allows a Python test function to take arguments independently provided
|
||||||
by factory functions. Factory functions allow to encapsulate
|
by factory functions. Factory functions allow to encapsulate
|
||||||
all setup and fixture glue code into nicely separated objects
|
all setup and fixture glue code into nicely separated objects
|
||||||
and provide a natural way for writing python test functions.
|
and provide a natural way for writing python test functions.
|
||||||
|
@ -14,7 +21,6 @@ Compared to `xUnit style`_ the new mechanism is meant to:
|
||||||
* bring new flexibility and power to test state management
|
* bring new flexibility and power to test state management
|
||||||
* naturally extend towards parametrizing test functions
|
* naturally extend towards parametrizing test functions
|
||||||
with multiple argument sets
|
with multiple argument sets
|
||||||
(superseding `old-style generative tests`_)
|
|
||||||
* enable creation of zero-boilerplate test helper objects that
|
* enable creation of zero-boilerplate test helper objects that
|
||||||
interact with the execution of a test function, see the
|
interact with the execution of a test function, see the
|
||||||
`blog post about the monkeypatch funcarg`_.
|
`blog post about the monkeypatch funcarg`_.
|
||||||
|
@ -26,272 +32,17 @@ the mechanism you are welcome to checkout `contact possibilities`_ page.
|
||||||
|
|
||||||
.. _`blog post about the monkeypatch funcarg`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/
|
.. _`blog post about the monkeypatch funcarg`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/
|
||||||
.. _`xUnit style`: xunit_setup.html
|
.. _`xUnit style`: xunit_setup.html
|
||||||
.. _`old-style generative tests`: features.html#generative-tests
|
|
||||||
|
|
||||||
.. _`funcarg factory`:
|
|
||||||
|
|
||||||
funcarg factories: setting up test function arguments
|
|
||||||
==============================================================
|
|
||||||
|
|
||||||
Test functions can specify one ore more arguments ("funcargs")
|
|
||||||
and a test module or plugin can define functions that provide
|
|
||||||
the function argument. Let's look at a simple self-contained
|
|
||||||
example that you can put into a test module:
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
# ./test_simplefactory.py
|
|
||||||
def pytest_funcarg__myfuncarg(request):
|
|
||||||
return 42
|
|
||||||
|
|
||||||
def test_function(myfuncarg):
|
|
||||||
assert myfuncarg == 17
|
|
||||||
|
|
||||||
If you run this with ``py.test test_simplefactory.py`` you see something like this:
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
============================ test session starts ============================
|
|
||||||
python: platform linux2 -- Python 2.6.2
|
|
||||||
test object 1: /home/hpk/hg/py/trunk/example/funcarg/test_simplefactory.py
|
|
||||||
|
|
||||||
test_simplefactory.py F
|
|
||||||
|
|
||||||
================================= FAILURES ==================================
|
|
||||||
_______________________________ test_function _______________________________
|
|
||||||
|
|
||||||
myfuncarg = 42
|
|
||||||
|
|
||||||
def test_function(myfuncarg):
|
|
||||||
> assert myfuncarg == 17
|
|
||||||
E assert 42 == 17
|
|
||||||
|
|
||||||
test_simplefactory.py:6: AssertionError
|
|
||||||
========================= 1 failed in 0.11 seconds ==========================
|
|
||||||
|
|
||||||
|
|
||||||
This means that the test function got executed and the assertion failed.
|
|
||||||
Here is how py.test comes to execute this test function:
|
|
||||||
|
|
||||||
1. py.test discovers the ``test_function`` because of the ``test_`` prefix.
|
|
||||||
The test function needs a function argument named ``myfuncarg``.
|
|
||||||
A matching factory function is discovered by looking for the special
|
|
||||||
name ``pytest_funcarg__myfuncarg``.
|
|
||||||
|
|
||||||
2. ``pytest_funcarg__myfuncarg(request)`` is called and
|
|
||||||
returns the value for ``myfuncarg``.
|
|
||||||
|
|
||||||
3. ``test_function(42)`` call is executed.
|
|
||||||
|
|
||||||
Note that if you misspell a function argument or want
|
|
||||||
to use one that isn't available, an error with a list of
|
|
||||||
available function argument is provided.
|
|
||||||
|
|
||||||
For more interesting factory functions that make good use of the
|
|
||||||
`request object`_ please see the `application setup tutorial example`_.
|
|
||||||
|
|
||||||
.. _`request object`:
|
|
||||||
|
|
||||||
funcarg factory request objects
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
Request objects are passed to funcarg factories and allow
|
|
||||||
to access test configuration, test context and `useful caching
|
|
||||||
and finalization helpers`_. Here is a list of attributes:
|
|
||||||
|
|
||||||
``request.function``: python function object requesting the argument
|
|
||||||
|
|
||||||
``request.cls``: class object where the test function is defined in or None.
|
|
||||||
|
|
||||||
``request.module``: module object where the test function is defined in.
|
|
||||||
|
|
||||||
``request.config``: access to command line opts and general config
|
|
||||||
|
|
||||||
``request.param``: if exists was passed by a `parametrizing test generator`_
|
|
||||||
|
|
||||||
.. _`useful caching and finalization helpers`:
|
|
||||||
|
|
||||||
|
|
||||||
registering funcarg related finalizers/cleanup
|
|
||||||
----------------------------------------------------
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
def addfinalizer(func):
|
|
||||||
""" call a finalizer function when test function finishes. """
|
|
||||||
|
|
||||||
Calling ``request.addfinalizer()`` is useful for scheduling teardown
|
|
||||||
functions. Here is an example for providing a ``myfile``
|
|
||||||
object that is to be closed when the execution of a
|
|
||||||
test function finishes.
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
def pytest_funcarg__myfile(self, request):
|
|
||||||
# ... create and open a unique per-function "myfile" object ...
|
|
||||||
request.addfinalizer(lambda: myfile.close())
|
|
||||||
return myfile
|
|
||||||
|
|
||||||
|
|
||||||
managing fixtures across test modules and test runs
|
|
||||||
----------------------------------------------------------
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
def cached_setup(setup, teardown=None, scope="module", extrakey=None):
|
|
||||||
""" cache and return result of calling setup().
|
|
||||||
|
|
||||||
The scope and the ``extrakey`` determine the cache key.
|
|
||||||
The scope also determines when teardown(result)
|
|
||||||
will be called. valid scopes are:
|
|
||||||
scope == 'function': when the single test function run finishes.
|
|
||||||
scope == 'module': when tests in a different module are run
|
|
||||||
scope == 'session': when tests of the session have run.
|
|
||||||
"""
|
|
||||||
|
|
||||||
Calling ``request.cached_setup()`` helps you to manage fixture
|
|
||||||
objects across several scopes. For example, for creating a Database object
|
|
||||||
that is to be setup only once during a test session you can use the helper
|
|
||||||
like this:
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
def pytest_funcarg__database(request):
|
|
||||||
return request.cached_setup(
|
|
||||||
setup=lambda: Database("..."),
|
|
||||||
teardown=lambda val: val.close(),
|
|
||||||
scope="session"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
requesting values of other funcargs
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
def getfuncargvalue(name):
|
|
||||||
""" Lookup and call function argument factory for the given name.
|
|
||||||
Each function argument is only created once per function setup.
|
|
||||||
"""
|
|
||||||
|
|
||||||
``request.getfuncargvalue(name)`` calls another funcarg factory function.
|
|
||||||
You can use this function if you want to `decorate a funcarg`_, i.e.
|
|
||||||
you want to provide the "normal" value but add something
|
|
||||||
extra. If a factory cannot be found a ``request.Error``
|
|
||||||
exception will be raised.
|
|
||||||
|
|
||||||
.. _`test generators`:
|
|
||||||
.. _`parametrizing test generator`:
|
|
||||||
|
|
||||||
generating parametrized tests with funcargs
|
|
||||||
===========================================================
|
|
||||||
|
|
||||||
You can parametrize multiple runs of the same test
|
|
||||||
function by adding new test function calls with different
|
|
||||||
function argument values. Let's look at a simple self-contained
|
|
||||||
example:
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
# ./test_example.py
|
|
||||||
def pytest_generate_tests(metafunc):
|
|
||||||
if "numiter" in metafunc.funcargnames:
|
|
||||||
for i in range(10):
|
|
||||||
metafunc.addcall(funcargs=dict(numiter=i))
|
|
||||||
|
|
||||||
def test_func(numiter):
|
|
||||||
assert numiter < 9
|
|
||||||
|
|
||||||
If you run this with ``py.test test_example.py`` you'll get:
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
================================= test session starts =================================
|
|
||||||
python: platform linux2 -- Python 2.6.2
|
|
||||||
test object 1: /home/hpk/hg/py/trunk/test_example.py
|
|
||||||
|
|
||||||
test_example.py .........F
|
|
||||||
|
|
||||||
====================================== FAILURES =======================================
|
|
||||||
_______________________________ test_func.test_func[9] ________________________________
|
|
||||||
|
|
||||||
numiter = 9
|
|
||||||
|
|
||||||
def test_func(numiter):
|
|
||||||
> assert numiter < 9
|
|
||||||
E assert 9 < 9
|
|
||||||
|
|
||||||
/home/hpk/hg/py/trunk/test_example.py:10: AssertionError
|
|
||||||
|
|
||||||
|
|
||||||
Here is what happens in detail:
|
|
||||||
|
|
||||||
1. ``pytest_generate_tests(metafunc)`` hook is called once for each test
|
|
||||||
function. It adds ten new function calls with explicit function arguments.
|
|
||||||
|
|
||||||
2. **execute tests**: ``test_func(numiter)`` is called ten times with
|
|
||||||
ten different arguments.
|
|
||||||
|
|
||||||
.. _`metafunc object`:
|
|
||||||
|
|
||||||
test generators and metafunc objects
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
metafunc objects are passed to the ``pytest_generate_tests`` hook.
|
|
||||||
They help to inspect a testfunction and to generate tests
|
|
||||||
according to test configuration or values specified
|
|
||||||
in the class or module where a test function is defined:
|
|
||||||
|
|
||||||
``metafunc.funcargnames``: set of required function arguments for given function
|
|
||||||
|
|
||||||
``metafunc.function``: underlying python test function
|
|
||||||
|
|
||||||
``metafunc.cls``: class object where the test function is defined in or None.
|
|
||||||
|
|
||||||
``metafunc.module``: the module object where the test function is defined in.
|
|
||||||
|
|
||||||
``metafunc.config``: access to command line opts and general config
|
|
||||||
|
|
||||||
|
|
||||||
the ``metafunc.addcall()`` method
|
|
||||||
-----------------------------------------------
|
|
||||||
|
|
||||||
.. sourcecode:: python
|
|
||||||
|
|
||||||
def addcall(funcargs={}, id=None, param=None):
|
|
||||||
""" trigger a new test function call. """
|
|
||||||
|
|
||||||
``funcargs`` can be a dictionary of argument names
|
|
||||||
mapped to values - providing it is called *direct parametrization*.
|
|
||||||
|
|
||||||
If you provide an `id`` it will be used for reporting
|
|
||||||
and identification purposes. If you don't supply an `id`
|
|
||||||
the stringified counter of the list of added calls will be used.
|
|
||||||
``id`` values needs to be unique between all
|
|
||||||
invocations for a given test function.
|
|
||||||
|
|
||||||
``param`` if specified will be seen by any
|
|
||||||
`funcarg factory`_ as a ``request.param`` attribute.
|
|
||||||
Setting it is called *indirect parametrization*.
|
|
||||||
|
|
||||||
Indirect parametrization is preferable if test values are
|
|
||||||
expensive to setup or can only be created in certain environments.
|
|
||||||
Test generators and thus ``addcall()`` invocations are performed
|
|
||||||
during test collection which is separate from the actual test
|
|
||||||
setup and test run phase. With distributed testing collection
|
|
||||||
and test setup/run happens in different process.
|
|
||||||
|
|
||||||
|
|
||||||
.. _`tutorial examples`:
|
.. _`tutorial examples`:
|
||||||
|
|
||||||
Funcarg Tutorial Examples
|
Tutorial Examples
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
|
|
||||||
.. _`application setup tutorial example`:
|
.. _`application setup tutorial example`:
|
||||||
.. _appsetup:
|
.. _appsetup:
|
||||||
|
|
||||||
application specific test setup
|
application specific test setup and fixtures
|
||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
|
|
||||||
Here is a basic useful step-wise example for handling application
|
Here is a basic useful step-wise example for handling application
|
||||||
|
@ -376,8 +127,9 @@ confused as to what the concrete question or answers actually mean,
|
||||||
please see here_ :) Otherwise proceed to step 2.
|
please see here_ :) Otherwise proceed to step 2.
|
||||||
|
|
||||||
.. _here: http://uncyclopedia.wikia.com/wiki/The_Hitchhiker's_Guide_to_the_Galaxy
|
.. _here: http://uncyclopedia.wikia.com/wiki/The_Hitchhiker's_Guide_to_the_Galaxy
|
||||||
.. _`local plugin`: extend.html#local-plugin
|
.. _`local plugin`: customize.html#local-plugin
|
||||||
|
|
||||||
|
.. _`tut-cmdlineoption`:
|
||||||
|
|
||||||
step 2: adding a command line option
|
step 2: adding a command line option
|
||||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
@ -521,25 +273,262 @@ the `py.path.local`_ class which provides many of the os.path
|
||||||
methods in a convenient way.
|
methods in a convenient way.
|
||||||
|
|
||||||
.. _`py.path.local`: ../path.html#local
|
.. _`py.path.local`: ../path.html#local
|
||||||
.. _`conftest plugin`: extend.html#conftestplugin
|
.. _`conftest plugin`: customize.html#conftestplugin
|
||||||
|
|
||||||
|
.. _`funcarg factory`:
|
||||||
|
|
||||||
|
funcarg factories: setting up test function arguments
|
||||||
|
==============================================================
|
||||||
|
|
||||||
|
Test functions can specify one ore more arguments ("funcargs")
|
||||||
|
and a test module or plugin can define functions that provide
|
||||||
|
the function argument. Let's look at a simple self-contained
|
||||||
|
example that you can put into a test module:
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
# ./test_simplefactory.py
|
||||||
|
def pytest_funcarg__myfuncarg(request):
|
||||||
|
return 42
|
||||||
|
|
||||||
|
def test_function(myfuncarg):
|
||||||
|
assert myfuncarg == 17
|
||||||
|
|
||||||
|
If you run this with ``py.test test_simplefactory.py`` you see something like this:
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
=========================== test session starts ============================
|
||||||
|
python: platform linux2 -- Python 2.6.2
|
||||||
|
test object 1: /home/hpk/hg/py/trunk/example/funcarg/test_simplefactory.py
|
||||||
|
|
||||||
|
test_simplefactory.py F
|
||||||
|
|
||||||
|
================================ FAILURES ==================================
|
||||||
|
______________________________ test_function _______________________________
|
||||||
|
|
||||||
|
myfuncarg = 42
|
||||||
|
|
||||||
|
def test_function(myfuncarg):
|
||||||
|
> assert myfuncarg == 17
|
||||||
|
E assert 42 == 17
|
||||||
|
|
||||||
|
test_simplefactory.py:6: AssertionError
|
||||||
|
======================== 1 failed in 0.11 seconds ==========================
|
||||||
|
|
||||||
|
|
||||||
Questions and Answers
|
This means that the test function got executed and the assertion failed.
|
||||||
==================================
|
Here is how py.test comes to execute this test function:
|
||||||
|
|
||||||
.. _`why pytest_pyfuncarg__ methods?`:
|
1. py.test discovers the ``test_function`` because of the ``test_`` prefix.
|
||||||
|
The test function needs a function argument named ``myfuncarg``.
|
||||||
|
A matching factory function is discovered by looking for the special
|
||||||
|
name ``pytest_funcarg__myfuncarg``.
|
||||||
|
|
||||||
Why ``pytest_funcarg__*`` methods?
|
2. ``pytest_funcarg__myfuncarg(request)`` is called and
|
||||||
------------------------------------
|
returns the value for ``myfuncarg``.
|
||||||
|
|
||||||
|
3. ``test_function(42)`` call is executed.
|
||||||
|
|
||||||
|
Note that if you misspell a function argument or want
|
||||||
|
to use one that isn't available, an error with a list of
|
||||||
|
available function argument is provided.
|
||||||
|
|
||||||
|
For more interesting factory functions that make good use of the
|
||||||
|
`request object`_ please see the `application setup tutorial example`_.
|
||||||
|
|
||||||
|
.. _`request object`:
|
||||||
|
|
||||||
|
funcarg factory request objects
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
Request objects are passed to funcarg factories and allow
|
||||||
|
to access test configuration, test context and `useful caching
|
||||||
|
and finalization helpers`_. Here is a list of attributes:
|
||||||
|
|
||||||
|
``request.function``: python function object requesting the argument
|
||||||
|
|
||||||
|
``request.cls``: class object where the test function is defined in or None.
|
||||||
|
|
||||||
|
``request.module``: module object where the test function is defined in.
|
||||||
|
|
||||||
|
``request.config``: access to command line opts and general config
|
||||||
|
|
||||||
|
``request.param``: if exists was passed by a previous `metafunc.addcall`_
|
||||||
|
|
||||||
|
.. _`useful caching and finalization helpers`:
|
||||||
|
|
||||||
|
|
||||||
|
registering funcarg related finalizers/cleanup
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
def addfinalizer(func):
|
||||||
|
""" call a finalizer function when test function finishes. """
|
||||||
|
|
||||||
|
Calling ``request.addfinalizer()`` is useful for scheduling teardown
|
||||||
|
functions. Here is an example for providing a ``myfile``
|
||||||
|
object that is to be closed when the execution of a
|
||||||
|
test function finishes.
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
def pytest_funcarg__myfile(self, request):
|
||||||
|
# ... create and open a unique per-function "myfile" object ...
|
||||||
|
request.addfinalizer(lambda: myfile.close())
|
||||||
|
return myfile
|
||||||
|
|
||||||
|
|
||||||
|
managing fixtures across test modules and test runs
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
def cached_setup(setup, teardown=None, scope="module", extrakey=None):
|
||||||
|
""" cache and return result of calling setup().
|
||||||
|
|
||||||
|
The scope and the ``extrakey`` determine the cache key.
|
||||||
|
The scope also determines when teardown(result)
|
||||||
|
will be called. valid scopes are:
|
||||||
|
scope == 'function': when the single test function run finishes.
|
||||||
|
scope == 'module': when tests in a different module are run
|
||||||
|
scope == 'session': when tests of the session have run.
|
||||||
|
"""
|
||||||
|
|
||||||
|
Calling ``request.cached_setup()`` helps you to manage fixture
|
||||||
|
objects across several scopes. For example, for creating a Database object
|
||||||
|
that is to be setup only once during a test session you can use the helper
|
||||||
|
like this:
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
def pytest_funcarg__database(request):
|
||||||
|
return request.cached_setup(
|
||||||
|
setup=lambda: Database("..."),
|
||||||
|
teardown=lambda val: val.close(),
|
||||||
|
scope="session"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
requesting values of other funcargs
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
def getfuncargvalue(name):
|
||||||
|
""" Lookup and call function argument factory for the given name.
|
||||||
|
Each function argument is only created once per function setup.
|
||||||
|
"""
|
||||||
|
|
||||||
|
``request.getfuncargvalue(name)`` calls another funcarg factory function.
|
||||||
|
You can use this function if you want to `decorate a funcarg`_, i.e.
|
||||||
|
you want to provide the "normal" value but add something
|
||||||
|
extra. If a factory cannot be found a ``request.Error``
|
||||||
|
exception will be raised.
|
||||||
|
|
||||||
|
.. _`test generators`:
|
||||||
|
.. _`parametrizing-tests`:
|
||||||
|
|
||||||
|
generating parametrized tests
|
||||||
|
===========================================================
|
||||||
|
|
||||||
|
You can parametrize multiple runs of the same test
|
||||||
|
function by adding new test function calls with different
|
||||||
|
function argument values. Let's look at a simple self-contained
|
||||||
|
example:
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
# ./test_example.py
|
||||||
|
def pytest_generate_tests(metafunc):
|
||||||
|
if "numiter" in metafunc.funcargnames:
|
||||||
|
for i in range(10):
|
||||||
|
metafunc.addcall(funcargs=dict(numiter=i))
|
||||||
|
|
||||||
|
def test_func(numiter):
|
||||||
|
assert numiter < 9
|
||||||
|
|
||||||
|
If you run this with ``py.test test_example.py`` you'll get:
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
============================= test session starts ==========================
|
||||||
|
python: platform linux2 -- Python 2.6.2
|
||||||
|
test object 1: /home/hpk/hg/py/trunk/test_example.py
|
||||||
|
|
||||||
|
test_example.py .........F
|
||||||
|
|
||||||
|
================================ FAILURES ==================================
|
||||||
|
__________________________ test_func.test_func[9] __________________________
|
||||||
|
|
||||||
|
numiter = 9
|
||||||
|
|
||||||
|
def test_func(numiter):
|
||||||
|
> assert numiter < 9
|
||||||
|
E assert 9 < 9
|
||||||
|
|
||||||
|
/home/hpk/hg/py/trunk/test_example.py:10: AssertionError
|
||||||
|
|
||||||
|
|
||||||
|
Here is what happens in detail:
|
||||||
|
|
||||||
|
1. ``pytest_generate_tests(metafunc)`` hook is called once for each test
|
||||||
|
function. It adds ten new function calls with explicit function arguments.
|
||||||
|
|
||||||
|
2. **execute tests**: ``test_func(numiter)`` is called ten times with
|
||||||
|
ten different arguments.
|
||||||
|
|
||||||
|
.. _`metafunc object`:
|
||||||
|
|
||||||
|
test generators and metafunc objects
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
metafunc objects are passed to the ``pytest_generate_tests`` hook.
|
||||||
|
They help to inspect a testfunction and to generate tests
|
||||||
|
according to test configuration or values specified
|
||||||
|
in the class or module where a test function is defined:
|
||||||
|
|
||||||
|
``metafunc.funcargnames``: set of required function arguments for given function
|
||||||
|
|
||||||
|
``metafunc.function``: underlying python test function
|
||||||
|
|
||||||
|
``metafunc.cls``: class object where the test function is defined in or None.
|
||||||
|
|
||||||
|
``metafunc.module``: the module object where the test function is defined in.
|
||||||
|
|
||||||
|
``metafunc.config``: access to command line opts and general config
|
||||||
|
|
||||||
|
|
||||||
|
.. _`metafunc.addcall`:
|
||||||
|
|
||||||
|
the ``metafunc.addcall()`` method
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
def addcall(funcargs={}, id=None, param=None):
|
||||||
|
""" trigger a new test function call. """
|
||||||
|
|
||||||
|
``funcargs`` can be a dictionary of argument names
|
||||||
|
mapped to values - providing it is called *direct parametrization*.
|
||||||
|
|
||||||
|
If you provide an `id`` it will be used for reporting
|
||||||
|
and identification purposes. If you don't supply an `id`
|
||||||
|
the stringified counter of the list of added calls will be used.
|
||||||
|
``id`` values needs to be unique between all
|
||||||
|
invocations for a given test function.
|
||||||
|
|
||||||
|
``param`` if specified will be seen by any
|
||||||
|
`funcarg factory`_ as a ``request.param`` attribute.
|
||||||
|
Setting it is called *indirect parametrization*.
|
||||||
|
|
||||||
|
Indirect parametrization is preferable if test values are
|
||||||
|
expensive to setup or can only be created in certain environments.
|
||||||
|
Test generators and thus ``addcall()`` invocations are performed
|
||||||
|
during test collection which is separate from the actual test
|
||||||
|
setup and test run phase. With distributed testing collection
|
||||||
|
and test setup/run happens in different process.
|
||||||
|
|
||||||
When experimenting with funcargs we also
|
|
||||||
considered an explicit registration mechanism, i.e. calling a register
|
|
||||||
method on the config object. But lacking a good use case for this
|
|
||||||
indirection and flexibility we decided to go for `Convention over
|
|
||||||
Configuration`_ and allow to directly specify the factory. It has the
|
|
||||||
positive implication that you should be able to "grep" for
|
|
||||||
``pytest_funcarg__MYARG`` and will find all providing sites (usually
|
|
||||||
exactly one).
|
|
||||||
|
|
||||||
.. _`Convention over Configuration`: http://en.wikipedia.org/wiki/Convention_over_Configuration
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
=======================================
|
||||||
|
py.test documentation index
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
|
||||||
|
features_: overview and discussion of features.
|
||||||
|
|
||||||
|
quickstart_: getting started with writing a simple test.
|
||||||
|
|
||||||
|
`talks, tutorials, examples`_: tutorial examples, slides
|
||||||
|
|
||||||
|
funcargs_: powerful parametrized test function setup
|
||||||
|
|
||||||
|
`plugins`_: list of available plugins with usage examples and feature details.
|
||||||
|
|
||||||
|
`distributed testing`_: ad-hoc run tests on multiple CPUs and platforms
|
||||||
|
|
||||||
|
customize_: configuration, customization, extensions
|
||||||
|
|
||||||
|
|
||||||
|
.. _`plugins`: plugin/index.html
|
||||||
|
.. _`talks, tutorials, examples`: talks.html
|
||||||
|
.. _quickstart: quickstart.html
|
||||||
|
.. _features: features.html
|
||||||
|
.. _funcargs: funcargs.html
|
||||||
|
.. _customize: customize.html
|
||||||
|
.. _`distributed testing`: dist.html
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
Mission
|
||||||
|
====================================
|
||||||
|
|
||||||
|
py.test strives to make testing a fun and no-boilerplate effort.
|
||||||
|
|
||||||
|
The tool is distributed as part of the `py` package which contains supporting APIs that
|
||||||
|
are also useable independently. The project independent ``py.test`` command line tool helps you to:
|
||||||
|
|
||||||
|
* rapidly collect and run tests
|
||||||
|
* run unit- or doctests, functional or integration tests
|
||||||
|
* distribute tests to multiple environments
|
||||||
|
* use local or global plugins for custom test types and setup
|
|
@ -38,7 +38,7 @@ You can influence output capturing mechanisms from the command line::
|
||||||
If you set capturing values in a conftest file like this::
|
If you set capturing values in a conftest file like this::
|
||||||
|
|
||||||
# conftest.py
|
# conftest.py
|
||||||
conf_capture = 'fd'
|
option_capture = 'fd'
|
||||||
|
|
||||||
then all tests in that directory will execute with "fd" style capturing.
|
then all tests in that directory will execute with "fd" style capturing.
|
||||||
|
|
||||||
|
@ -120,12 +120,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_capture.py`_ plugin source code
|
1. Download `pytest_capture.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_capture.py`` into your import path
|
2. put it somewhere as ``pytest_capture.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -29,12 +29,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_doctest.py`_ plugin source code
|
1. Download `pytest_doctest.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_doctest.py`` into your import path
|
2. put it somewhere as ``pytest_doctest.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -24,12 +24,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_figleaf.py`_ plugin source code
|
1. Download `pytest_figleaf.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_figleaf.py`` into your import path
|
2. put it somewhere as ``pytest_figleaf.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
pytest_helpconfig plugin
|
||||||
|
========================
|
||||||
|
|
||||||
|
provide version info, conftest/environment config names.
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
command line options
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
|
||||||
|
``--help-config``
|
||||||
|
show available conftest.py and ENV-variable names.
|
||||||
|
``--version``
|
||||||
|
display py lib version and import information.
|
||||||
|
|
||||||
|
Start improving this plugin in 30 seconds
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
|
1. Download `pytest_helpconfig.py`_ plugin source code
|
||||||
|
2. put it somewhere as ``pytest_helpconfig.py`` into your import path
|
||||||
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
|
.. include:: links.txt
|
|
@ -20,12 +20,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_hooklog.py`_ plugin source code
|
1. Download `pytest_hooklog.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_hooklog.py`` into your import path
|
2. put it somewhere as ``pytest_hooklog.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -97,7 +97,7 @@ hook specification sourcecode
|
||||||
""" called before test session finishes. """
|
""" called before test session finishes. """
|
||||||
pytest__teardown_final.firstresult = True
|
pytest__teardown_final.firstresult = True
|
||||||
|
|
||||||
def pytest__teardown_final_logerror(rep):
|
def pytest__teardown_final_logerror(report):
|
||||||
""" called if runtest_teardown_final failed. """
|
""" called if runtest_teardown_final failed. """
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
@ -114,8 +114,8 @@ hook specification sourcecode
|
||||||
# hooks for influencing reporting (invoked from pytest_terminal)
|
# hooks for influencing reporting (invoked from pytest_terminal)
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
def pytest_report_teststatus(rep):
|
def pytest_report_teststatus(report):
|
||||||
""" return shortletter and verbose word. """
|
""" return result-category, shortletter and verbose word for reporting."""
|
||||||
pytest_report_teststatus.firstresult = True
|
pytest_report_teststatus.firstresult = True
|
||||||
|
|
||||||
def pytest_terminal_summary(terminalreporter):
|
def pytest_terminal_summary(terminalreporter):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
Plugins related to Python test functions and programs
|
plugins for Python test functions
|
||||||
=====================================================
|
=================================
|
||||||
|
|
||||||
xfail_ mark python test functions as expected-to-fail and report them separately.
|
xfail_ mark python test functions as expected-to-fail and report them separately.
|
||||||
|
|
||||||
|
@ -13,19 +13,21 @@ capture_ configurable per-test stdout/stderr capturing mechanisms.
|
||||||
recwarn_ helpers for asserting deprecation and other warnings.
|
recwarn_ helpers for asserting deprecation and other warnings.
|
||||||
|
|
||||||
|
|
||||||
Plugins for other testing styles and languages
|
plugins for other testing styles and languages
|
||||||
==============================================
|
==============================================
|
||||||
|
|
||||||
|
oejskit_ run javascript tests in real life browsers
|
||||||
|
|
||||||
unittest_ automatically discover and run traditional "unittest.py" style tests.
|
unittest_ automatically discover and run traditional "unittest.py" style tests.
|
||||||
|
|
||||||
doctest_ collect and execute doctests from modules and test files.
|
nose_ nose-compatibility plugin: allow to run nose test suites natively.
|
||||||
|
|
||||||
oejskit_ run javascript tests in real life browsers
|
doctest_ collect and execute doctests from modules and test files.
|
||||||
|
|
||||||
restdoc_ perform ReST syntax, local and remote reference tests on .rst/.txt files.
|
restdoc_ perform ReST syntax, local and remote reference tests on .rst/.txt files.
|
||||||
|
|
||||||
|
|
||||||
Plugins for generic reporting and failure logging
|
plugins for generic reporting and failure logging
|
||||||
=================================================
|
=================================================
|
||||||
|
|
||||||
pastebin_ submit failure or test session information to a pastebin service.
|
pastebin_ submit failure or test session information to a pastebin service.
|
||||||
|
@ -35,8 +37,20 @@ resultlog_ resultlog plugin for machine-readable logging of test results.
|
||||||
terminal_ Implements terminal reporting of the full testing process.
|
terminal_ Implements terminal reporting of the full testing process.
|
||||||
|
|
||||||
|
|
||||||
internal plugins / core functionality
|
plugins for generic reporting and failure logging
|
||||||
=====================================
|
=================================================
|
||||||
|
|
||||||
|
pastebin_ submit failure or test session information to a pastebin service.
|
||||||
|
|
||||||
|
resultlog_ resultlog plugin for machine-readable logging of test results.
|
||||||
|
|
||||||
|
terminal_ Implements terminal reporting of the full testing process.
|
||||||
|
|
||||||
|
|
||||||
|
misc plugins / core functionality
|
||||||
|
=================================
|
||||||
|
|
||||||
|
helpconfig_ provide version info, conftest/environment config names.
|
||||||
|
|
||||||
pdb_ interactive debugging with the Python Debugger.
|
pdb_ interactive debugging with the Python Debugger.
|
||||||
|
|
||||||
|
|
|
@ -35,12 +35,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_keyword.py`_ plugin source code
|
1. Download `pytest_keyword.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_keyword.py`` into your import path
|
2. put it somewhere as ``pytest_keyword.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -1,33 +1,37 @@
|
||||||
|
.. _`helpconfig`: helpconfig.html
|
||||||
.. _`terminal`: terminal.html
|
.. _`terminal`: terminal.html
|
||||||
.. _`pytest_recwarn.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_recwarn.py
|
.. _`pytest_recwarn.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_recwarn.py
|
||||||
.. _`unittest`: unittest.html
|
.. _`unittest`: unittest.html
|
||||||
.. _`pytest_monkeypatch.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_monkeypatch.py
|
.. _`pytest_monkeypatch.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_monkeypatch.py
|
||||||
.. _`pytest_keyword.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_keyword.py
|
.. _`pytest_keyword.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_keyword.py
|
||||||
.. _`pastebin`: pastebin.html
|
.. _`pastebin`: pastebin.html
|
||||||
.. _`plugins`: index.html
|
.. _`plugins`: index.html
|
||||||
.. _`pytest_capture.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_capture.py
|
.. _`pytest_capture.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_capture.py
|
||||||
.. _`pytest_doctest.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_doctest.py
|
.. _`pytest_doctest.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_doctest.py
|
||||||
.. _`capture`: capture.html
|
.. _`capture`: capture.html
|
||||||
.. _`hooklog`: hooklog.html
|
.. _`pytest_nose.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_nose.py
|
||||||
.. _`pytest_restdoc.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_restdoc.py
|
.. _`pytest_restdoc.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_restdoc.py
|
||||||
.. _`pytest_hooklog.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_hooklog.py
|
|
||||||
.. _`pytest_pastebin.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_pastebin.py
|
|
||||||
.. _`pytest_figleaf.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_figleaf.py
|
|
||||||
.. _`xfail`: xfail.html
|
.. _`xfail`: xfail.html
|
||||||
.. _`contact`: ../../contact.html
|
.. _`pytest_pastebin.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_pastebin.py
|
||||||
|
.. _`pytest_figleaf.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_figleaf.py
|
||||||
|
.. _`pytest_hooklog.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_hooklog.py
|
||||||
.. _`checkout the py.test development version`: ../../download.html#checkout
|
.. _`checkout the py.test development version`: ../../download.html#checkout
|
||||||
|
.. _`pytest_helpconfig.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_helpconfig.py
|
||||||
.. _`oejskit`: oejskit.html
|
.. _`oejskit`: oejskit.html
|
||||||
.. _`pytest_xfail.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_xfail.py
|
.. _`doctest`: doctest.html
|
||||||
|
.. _`get in contact`: ../../contact.html
|
||||||
|
.. _`pytest_xfail.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_xfail.py
|
||||||
.. _`figleaf`: figleaf.html
|
.. _`figleaf`: figleaf.html
|
||||||
.. _`extend`: ../extend.html
|
.. _`customize`: ../customize.html
|
||||||
.. _`pytest_terminal.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_terminal.py
|
.. _`hooklog`: hooklog.html
|
||||||
|
.. _`pytest_terminal.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_terminal.py
|
||||||
.. _`recwarn`: recwarn.html
|
.. _`recwarn`: recwarn.html
|
||||||
.. _`pytest_pdb.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_pdb.py
|
.. _`pytest_pdb.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_pdb.py
|
||||||
.. _`monkeypatch`: monkeypatch.html
|
.. _`monkeypatch`: monkeypatch.html
|
||||||
.. _`resultlog`: resultlog.html
|
.. _`resultlog`: resultlog.html
|
||||||
.. _`keyword`: keyword.html
|
.. _`keyword`: keyword.html
|
||||||
.. _`restdoc`: restdoc.html
|
.. _`restdoc`: restdoc.html
|
||||||
.. _`pytest_unittest.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_unittest.py
|
.. _`pytest_unittest.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_unittest.py
|
||||||
.. _`doctest`: doctest.html
|
.. _`nose`: nose.html
|
||||||
.. _`pytest_resultlog.py`: http://bitbucket.org/hpk42/py-trunk/raw/caf81a2cdf5083be3bfb715d7e56273330a54843/py/test/plugin/pytest_resultlog.py
|
.. _`pytest_resultlog.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_resultlog.py
|
||||||
.. _`pdb`: pdb.html
|
.. _`pdb`: pdb.html
|
||||||
|
|
|
@ -10,7 +10,7 @@ safely patch object attributes, dicts and environment variables.
|
||||||
Usage
|
Usage
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
Use the `monkeypatch funcarg`_ to safely patch the environment
|
Use the `monkeypatch funcarg`_ to safely patch environment
|
||||||
variables, object attributes or dictionaries. For example, if you want
|
variables, object attributes or dictionaries. For example, if you want
|
||||||
to set the environment variable ``ENV1`` and patch the
|
to set the environment variable ``ENV1`` and patch the
|
||||||
``os.path.abspath`` function to return a particular value during a test
|
``os.path.abspath`` function to return a particular value during a test
|
||||||
|
@ -28,6 +28,15 @@ old state. After the test function finished execution all
|
||||||
modifications will be reverted. See the `monkeypatch blog post`_
|
modifications will be reverted. See the `monkeypatch blog post`_
|
||||||
for an extensive discussion.
|
for an extensive discussion.
|
||||||
|
|
||||||
|
To add to a possibly existing environment parameter you
|
||||||
|
can use this example:
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
def test_mypath_finding(monkeypatch):
|
||||||
|
monkeypatch.setenv('PATH', 'x/y', prepend=":")
|
||||||
|
# x/y will be at the beginning of $PATH
|
||||||
|
|
||||||
.. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/
|
.. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/
|
||||||
|
|
||||||
.. _`monkeypatch funcarg`:
|
.. _`monkeypatch funcarg`:
|
||||||
|
@ -50,12 +59,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_monkeypatch.py`_ plugin source code
|
1. Download `pytest_monkeypatch.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_monkeypatch.py`` into your import path
|
2. put it somewhere as ``pytest_monkeypatch.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -8,40 +8,26 @@ nose-compatibility plugin: allow to run nose test suites natively.
|
||||||
:local:
|
:local:
|
||||||
|
|
||||||
This is an experimental plugin for allowing to run tests written
|
This is an experimental plugin for allowing to run tests written
|
||||||
in the 'nosetests' style with py.test.
|
in 'nosetests' style with py.test.
|
||||||
nosetests is a popular clone
|
|
||||||
of py.test and thus shares some philosophy. This plugin is an
|
|
||||||
attempt to understand and neutralize differences. It allows to
|
|
||||||
run nosetests' own test suite and a number of other test suites
|
|
||||||
without problems.
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
If you type::
|
type::
|
||||||
|
|
||||||
py.test -p nose
|
py.test # instead of 'nosetests'
|
||||||
|
|
||||||
where you would type ``nosetests``, you can run your nose style tests.
|
and you should be able to run nose style tests. You will of course
|
||||||
You might also try to run without the nose plugin to see where your test
|
get py.test style reporting and its feature set.
|
||||||
suite is incompatible to the default py.test.
|
|
||||||
|
|
||||||
To avoid the need for specifying a command line option you can set an environment
|
Issues?
|
||||||
variable::
|
----------------
|
||||||
|
|
||||||
PYTEST_PLUGINS=nose
|
If you find issues or have suggestions please run::
|
||||||
|
|
||||||
or create a ``conftest.py`` file in your test directory or below::
|
py.test --pastebin=all
|
||||||
|
|
||||||
# conftest.py
|
and send the resulting URL to a some contact channel.
|
||||||
pytest_plugins = "nose",
|
|
||||||
|
|
||||||
If you find issues or have suggestions you may run::
|
|
||||||
|
|
||||||
py.test -p nose --pastebin=all
|
|
||||||
|
|
||||||
to create a URL of a test run session and send it with comments to the issue
|
|
||||||
tracker or mailing list.
|
|
||||||
|
|
||||||
Known issues
|
Known issues
|
||||||
------------------
|
------------------
|
||||||
|
@ -49,16 +35,16 @@ Known issues
|
||||||
- nose-style doctests are not collected and executed correctly,
|
- nose-style doctests are not collected and executed correctly,
|
||||||
also fixtures don't work.
|
also fixtures don't work.
|
||||||
|
|
||||||
|
- no nose-configuration is recognized
|
||||||
|
|
||||||
Start improving this plugin in 30 seconds
|
Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_nose.py`_ plugin source code
|
1. Download `pytest_nose.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_nose.py`` into your import path
|
2. put it somewhere as ``pytest_nose.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -14,7 +14,7 @@ Usage
|
||||||
|
|
||||||
py.test --pastebin=failed
|
py.test --pastebin=failed
|
||||||
|
|
||||||
This will submit full failure information to a remote Paste service and
|
This will submit test run information to a remote Paste service and
|
||||||
provide a URL for each failure. You may select tests as usual or add
|
provide a URL for each failure. You may select tests as usual or add
|
||||||
for example ``-x`` if you only want to send one particular failure.
|
for example ``-x`` if you only want to send one particular failure.
|
||||||
|
|
||||||
|
@ -35,12 +35,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_pastebin.py`_ plugin source code
|
1. Download `pytest_pastebin.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_pastebin.py`` into your import path
|
2. put it somewhere as ``pytest_pastebin.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -20,12 +20,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_pdb.py`_ plugin source code
|
1. Download `pytest_pdb.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_pdb.py`` into your import path
|
2. put it somewhere as ``pytest_pdb.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -50,12 +50,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_recwarn.py`_ plugin source code
|
1. Download `pytest_recwarn.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_recwarn.py`` into your import path
|
2. put it somewhere as ``pytest_recwarn.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -24,12 +24,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_restdoc.py`_ plugin source code
|
1. Download `pytest_restdoc.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_restdoc.py`` into your import path
|
2. put it somewhere as ``pytest_restdoc.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -20,12 +20,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_resultlog.py`_ plugin source code
|
1. Download `pytest_resultlog.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_resultlog.py`` into your import path
|
2. put it somewhere as ``pytest_resultlog.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -28,12 +28,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_terminal.py`_ plugin source code
|
1. Download `pytest_terminal.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_terminal.py`` into your import path
|
2. put it somewhere as ``pytest_terminal.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -23,12 +23,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_unittest.py`_ plugin source code
|
1. Download `pytest_unittest.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_unittest.py`` into your import path
|
2. put it somewhere as ``pytest_unittest.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -25,12 +25,10 @@ Start improving this plugin in 30 seconds
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Do you find the above documentation or the plugin itself lacking?
|
|
||||||
|
|
||||||
1. Download `pytest_xfail.py`_ plugin source code
|
1. Download `pytest_xfail.py`_ plugin source code
|
||||||
2. put it somewhere as ``pytest_xfail.py`` into your import path
|
2. put it somewhere as ``pytest_xfail.py`` into your import path
|
||||||
3. a subsequent ``py.test`` run will use your local version
|
3. a subsequent ``py.test`` run will use your local version
|
||||||
|
|
||||||
Further information: extend_ documentation, other plugins_ or contact_.
|
Checkout customize_, other plugins_ or `get in contact`_.
|
||||||
|
|
||||||
.. include:: links.txt
|
.. include:: links.txt
|
||||||
|
|
|
@ -7,27 +7,61 @@ Quickstart
|
||||||
|
|
||||||
.. _here: ../download.html#no-setuptools
|
.. _here: ../download.html#no-setuptools
|
||||||
|
|
||||||
This document assumes basic python knowledge and a working `setuptools
|
|
||||||
installation`_ (otherwise see here_). You can install
|
With a `setuptools installation`_ (otherwise see here_) you can type::
|
||||||
the py lib and py.test by typing::
|
|
||||||
|
|
||||||
easy_install -U py
|
easy_install -U py
|
||||||
|
|
||||||
Now open a file ``test_sample.py`` file and put the following
|
On Linux systems you may need to execute this as the superuser and
|
||||||
example content into it::
|
on Windows you might need to write down the full path to ``easy_install``.
|
||||||
|
|
||||||
|
Now create a file ``test_sample.py`` with the following content:
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
# content of test_sample.py
|
# content of test_sample.py
|
||||||
|
def func(x):
|
||||||
|
return x + 1
|
||||||
def test_answer():
|
def test_answer():
|
||||||
assert 42 == 43
|
assert f(3) == 5
|
||||||
|
|
||||||
You can now run the test file like this::
|
You can now run the test file like this::
|
||||||
|
|
||||||
py.test test_sample.py
|
py.test test_sample.py
|
||||||
|
|
||||||
and will see an error report on the failing assert statement.
|
and will see output like this:
|
||||||
For further information please refer to `features`_
|
|
||||||
or checkout the `tutorials`_ page for more introduction material.
|
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
=========================== test session starts ============================
|
||||||
|
python: platform linux2 -- Python 2.6.2
|
||||||
|
test object 1: test_sample.py
|
||||||
|
|
||||||
|
test_sample.py F
|
||||||
|
|
||||||
|
================================= FAILURES =================================
|
||||||
|
_______________________________ test_answer ________________________________
|
||||||
|
|
||||||
|
def test_answer():
|
||||||
|
> assert func(3) == 5
|
||||||
|
E assert 4 == 5
|
||||||
|
E + where 4 = func(3)
|
||||||
|
|
||||||
|
test_sample.py:6: AssertionError
|
||||||
|
========================= 1 failed in 0.08 seconds =========================
|
||||||
|
|
||||||
|
This output contains Python interpreter information, a list of test objects,
|
||||||
|
a progress report and important details of the failure.
|
||||||
|
|
||||||
|
**Where to go from here**
|
||||||
|
|
||||||
|
`tutorials`_: a collection of starting points with code examples
|
||||||
|
|
||||||
|
`features`_: overview and description of test features
|
||||||
|
|
||||||
|
`contact`_: many ways for feedback and questions
|
||||||
|
|
||||||
|
.. _`contact`: ../contact.html
|
||||||
.. _`automatically collected`: features.html#autocollect
|
.. _`automatically collected`: features.html#autocollect
|
||||||
.. _download: ../download.html
|
.. _download: ../download.html
|
||||||
.. _features: features.html
|
.. _features: features.html
|
||||||
|
|
|
@ -9,25 +9,27 @@ tutorial examples and blog postings
|
||||||
|
|
||||||
function arguments:
|
function arguments:
|
||||||
|
|
||||||
- `application setup in test functions with funcargs`_ (doc link)
|
- `application setup in test functions with funcargs`_
|
||||||
|
- `making funcargs dependendent on command line options`_
|
||||||
- `monkey patching done right`_ (blog post, consult `monkeypatch
|
- `monkey patching done right`_ (blog post, consult `monkeypatch
|
||||||
plugin`_ for actual 1.0 API)
|
plugin`_ for actual 1.0 API)
|
||||||
|
|
||||||
test parametrization:
|
test parametrization:
|
||||||
|
|
||||||
- `generating parametrized tests with funcargs`_ (doc link)
|
- `generating parametrized tests with funcargs`_
|
||||||
- `parametrizing tests, generalized`_ (blog entry)
|
- `parametrizing tests, generalized`_ (blog post)
|
||||||
- `putting test-hooks into local or global plugins`_ (blog entry)
|
- `putting test-hooks into local or global plugins`_ (blog post)
|
||||||
|
|
||||||
distributed testing:
|
distributed testing:
|
||||||
|
|
||||||
- `simultanously test your code on all platforms`_ (blog entry)
|
- `simultanously test your code on all platforms`_ (blog entry)
|
||||||
|
|
||||||
plugins:
|
plugin specific examples:
|
||||||
|
|
||||||
- usage examples are in most of the referenced `plugins`_ docs
|
- `many examples in the docs for plugins`_
|
||||||
|
|
||||||
.. _plugins: plugin/index.html
|
.. _`making funcargs dependendent on command line options`: funcargs.html#tut-cmdlineoption
|
||||||
|
.. _`many examples in the docs for plugins`: plugin/index.html
|
||||||
.. _`monkeypatch plugin`: plugin/monkeypatch.html
|
.. _`monkeypatch plugin`: plugin/monkeypatch.html
|
||||||
.. _`application setup in test functions with funcargs`: funcargs.html#appsetup
|
.. _`application setup in test functions with funcargs`: funcargs.html#appsetup
|
||||||
.. _`simultanously test your code on all platforms`: http://tetamap.wordpress.com/2009/03/23/new-simultanously-test-your-code-on-all-platforms/
|
.. _`simultanously test your code on all platforms`: http://tetamap.wordpress.com/2009/03/23/new-simultanously-test-your-code-on-all-platforms/
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="refresh" content=" 1 ; URL=index.html" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||||
|
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var pageTracker = _gat._getTracker("UA-7597274-3");
|
||||||
|
pageTracker._trackPageview();
|
||||||
|
} catch(err) {}</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
=======================================
|
|
||||||
py.test documentation index
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
the project independent ``py.test`` command line tool helps you to:
|
|
||||||
|
|
||||||
* rapidly collect and run tests
|
|
||||||
* run unit- or doctests, functional or integration tests
|
|
||||||
* distribute tests to multiple environments
|
|
||||||
* use local or global plugins for custom test types and setup
|
|
||||||
|
|
||||||
quickstart_: for getting started immediately.
|
|
||||||
|
|
||||||
features_: a walk through basic features and usage.
|
|
||||||
|
|
||||||
`talks, tutorials, examples`_: tutorial examples, slides
|
|
||||||
|
|
||||||
`available plugins`_: list of py.test plugins
|
|
||||||
|
|
||||||
funcargs_: powerful parametrized test function setup
|
|
||||||
|
|
||||||
`distributed testing`_: distribute test runs to other machines and platforms.
|
|
||||||
|
|
||||||
extend_: intro to extend and customize py.test runs
|
|
||||||
|
|
||||||
config_: ``conftest.py`` files and the config object
|
|
||||||
|
|
||||||
|
|
||||||
.. _`available plugins`: plugin/index.html
|
|
||||||
.. _`talks, tutorials, examples`: talks.html
|
|
||||||
.. _quickstart: quickstart.html
|
|
||||||
.. _features: features.html
|
|
||||||
.. _funcargs: funcargs.html
|
|
||||||
.. _extend: extend.html
|
|
||||||
.. _config: config.html
|
|
||||||
.. _`distributed testing`: dist.html
|
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,10 @@ xUnit style setup
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
|
|
||||||
Since version 1.0 py.test offers funcargs_ for both
|
Since version 1.0 funcargs_ present the recommended way
|
||||||
simple and complex test setup needs. Especially
|
to manage flexible and scalable test setups.
|
||||||
for functional and integration, but also for unit testing, it is
|
|
||||||
highly recommended that you use this new method.
|
|
||||||
|
|
||||||
Python, Java and other languages have a tradition
|
Python, Java and many other languages have a tradition
|
||||||
of using xUnit_ style testing. This typically
|
of using xUnit_ style testing. This typically
|
||||||
involves the call of a ``setup`` method before
|
involves the call of a ``setup`` method before
|
||||||
a test function is run and ``teardown`` after
|
a test function is run and ``teardown`` after
|
||||||
|
|
|
@ -166,4 +166,4 @@ complete the probably request-specific serialization of
|
||||||
your Tags. Hum, it's probably harder to explain this than to
|
your Tags. Hum, it's probably harder to explain this than to
|
||||||
actually code it :-)
|
actually code it :-)
|
||||||
|
|
||||||
.. _`py.test`: test/test.html
|
.. _`py.test`: test/index.html
|
||||||
|
|
|
@ -11,6 +11,13 @@ def otherfunc_multi(a,b):
|
||||||
assert (a ==
|
assert (a ==
|
||||||
b)
|
b)
|
||||||
|
|
||||||
|
def test_generative(param1, param2):
|
||||||
|
assert param1 * 2 < param2
|
||||||
|
|
||||||
|
def pytest_generate_tests(metafunc):
|
||||||
|
if 'param1' in metafunc.funcargnames:
|
||||||
|
metafunc.addcall(funcargs=dict(param1=3, param2=6))
|
||||||
|
|
||||||
class TestFailing(object):
|
class TestFailing(object):
|
||||||
def test_simple(self):
|
def test_simple(self):
|
||||||
def f():
|
def f():
|
||||||
|
@ -96,14 +103,9 @@ class TestFailing(object):
|
||||||
if namenotexi:
|
if namenotexi:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_generator(self):
|
|
||||||
yield None
|
|
||||||
|
|
||||||
def func1(self):
|
def func1(self):
|
||||||
assert 41 == 42
|
assert 41 == 42
|
||||||
|
|
||||||
def test_generator2(self):
|
|
||||||
yield self.func1
|
|
||||||
|
|
||||||
# thanks to Matthew Scott for this test
|
# thanks to Matthew Scott for this test
|
||||||
def test_dynamic_compile_shows_nicely():
|
def test_dynamic_compile_shows_nicely():
|
||||||
|
|
|
@ -11,4 +11,4 @@ def test_failure_demo_fails_properly(testdir):
|
||||||
assert failed == 20, failed
|
assert failed == 20, failed
|
||||||
colreports = reprec.getreports("pytest_collectreport")
|
colreports = reprec.getreports("pytest_collectreport")
|
||||||
failed = len([x.failed for x in colreports])
|
failed = len([x.failed for x in colreports])
|
||||||
assert failed == 5
|
assert failed == 4
|
||||||
|
|
|
@ -64,7 +64,7 @@ class Config(object):
|
||||||
val = eval(val)
|
val = eval(val)
|
||||||
opt.default = val
|
opt.default = val
|
||||||
else:
|
else:
|
||||||
name = "pytest_option_" + opt.dest
|
name = "option_" + opt.dest
|
||||||
try:
|
try:
|
||||||
opt.default = self._conftest.rget(name)
|
opt.default = self._conftest.rget(name)
|
||||||
except (ValueError, KeyError):
|
except (ValueError, KeyError):
|
||||||
|
|
|
@ -10,6 +10,5 @@ Generator = py.test.collect.Generator
|
||||||
Function = py.test.collect.Function
|
Function = py.test.collect.Function
|
||||||
Instance = py.test.collect.Instance
|
Instance = py.test.collect.Instance
|
||||||
|
|
||||||
pytest_plugins = "default runner capture terminal keyword xfail tmpdir execnetcleanup monkeypatch recwarn pdb pastebin unittest".split()
|
pytest_plugins = "default runner capture terminal keyword xfail tmpdir execnetcleanup monkeypatch recwarn pdb pastebin unittest helpconfig nose".split()
|
||||||
|
|
||||||
conf_capture = "fd"
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ class TestDistribution:
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
testdir.makeconftest("""
|
testdir.makeconftest("""
|
||||||
pytest_option_tx = 'popen popen popen'.split()
|
option_tx = 'popen popen popen'.split()
|
||||||
""")
|
""")
|
||||||
result = testdir.runpytest(p1, '-d')
|
result = testdir.runpytest(p1, '-d')
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
|
|
|
@ -32,7 +32,7 @@ You can influence output capturing mechanisms from the command line::
|
||||||
If you set capturing values in a conftest file like this::
|
If you set capturing values in a conftest file like this::
|
||||||
|
|
||||||
# conftest.py
|
# conftest.py
|
||||||
conf_capture = 'fd'
|
option_capture = 'fd'
|
||||||
|
|
||||||
then all tests in that directory will execute with "fd" style capturing.
|
then all tests in that directory will execute with "fd" style capturing.
|
||||||
|
|
||||||
|
@ -110,8 +110,8 @@ class CaptureManager:
|
||||||
def _maketempfile(self):
|
def _maketempfile(self):
|
||||||
f = py.std.tempfile.TemporaryFile()
|
f = py.std.tempfile.TemporaryFile()
|
||||||
newf = py.io.dupfile(f)
|
newf = py.io.dupfile(f)
|
||||||
f.close()
|
encoding = getattr(newf, 'encoding', None) or "UTF-8"
|
||||||
return ustream(newf)
|
return EncodedFile(newf, encoding)
|
||||||
|
|
||||||
def _makestringio(self):
|
def _makestringio(self):
|
||||||
return py.std.StringIO.StringIO()
|
return py.std.StringIO.StringIO()
|
||||||
|
@ -131,7 +131,10 @@ class CaptureManager:
|
||||||
def _getmethod(self, config, fspath):
|
def _getmethod(self, config, fspath):
|
||||||
if config.option.capture:
|
if config.option.capture:
|
||||||
return config.option.capture
|
return config.option.capture
|
||||||
return config._conftest.rget("conf_capture", path=fspath)
|
try:
|
||||||
|
return config._conftest.rget("option_capture", path=fspath)
|
||||||
|
except KeyError:
|
||||||
|
return "fd"
|
||||||
|
|
||||||
def resumecapture_item(self, item):
|
def resumecapture_item(self, item):
|
||||||
method = self._getmethod(item.config, item.fspath)
|
method = self._getmethod(item.config, item.fspath)
|
||||||
|
@ -266,12 +269,21 @@ class CaptureFuncarg:
|
||||||
self.capture.reset()
|
self.capture.reset()
|
||||||
del self.capture
|
del self.capture
|
||||||
|
|
||||||
def ustream(f):
|
class EncodedFile(object):
|
||||||
import codecs
|
def __init__(self, _stream, encoding):
|
||||||
encoding = getattr(f, 'encoding', None) or "UTF-8"
|
self._stream = _stream
|
||||||
reader = codecs.getreader(encoding)
|
self.encoding = encoding
|
||||||
writer = codecs.getwriter(encoding)
|
|
||||||
srw = codecs.StreamReaderWriter(f, reader, writer)
|
def write(self, obj):
|
||||||
srw.encoding = encoding
|
if isinstance(obj, unicode):
|
||||||
return srw
|
self._stream.write(obj.encode(self.encoding))
|
||||||
|
else:
|
||||||
|
self._stream.write(obj)
|
||||||
|
|
||||||
|
def writelines(self, linelist):
|
||||||
|
data = ''.join(linelist)
|
||||||
|
self.write(data)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self._stream, name)
|
||||||
|
|
||||||
|
|
|
@ -61,13 +61,13 @@ def pytest_addoption(parser):
|
||||||
action="store", dest="tbstyle", default='long',
|
action="store", dest="tbstyle", default='long',
|
||||||
type="choice", choices=['long', 'short', 'no'],
|
type="choice", choices=['long', 'short', 'no'],
|
||||||
help="traceback verboseness (long/short/no).")
|
help="traceback verboseness (long/short/no).")
|
||||||
group._addoption('-p', action="append", dest="plugin", default = [],
|
group._addoption('-p', action="append", dest="plugins", default = [],
|
||||||
help=("load the specified plugin after command line parsing. "))
|
help=("load the specified plugin after command line parsing. "))
|
||||||
group._addoption('-f', '--looponfail',
|
group._addoption('-f', '--looponfail',
|
||||||
action="store_true", dest="looponfail", default=False,
|
action="store_true", dest="looponfail", default=False,
|
||||||
help="run tests, re-run failing test set until all pass.")
|
help="run tests, re-run failing test set until all pass.")
|
||||||
|
|
||||||
group = parser.addgroup("test process debugging")
|
group = parser.addgroup("debugconfig", "test process debugging and configuration")
|
||||||
group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir",
|
group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir",
|
||||||
help="base temporary directory for this test run.")
|
help="base temporary directory for this test run.")
|
||||||
|
|
||||||
|
@ -91,17 +91,10 @@ def pytest_addoption(parser):
|
||||||
help="shortcut for '--dist=load --tx=NUM*popen'")
|
help="shortcut for '--dist=load --tx=NUM*popen'")
|
||||||
group.addoption('--rsyncdir', action="append", default=[], metavar="dir1",
|
group.addoption('--rsyncdir', action="append", default=[], metavar="dir1",
|
||||||
help="add directory for rsyncing to remote tx nodes.")
|
help="add directory for rsyncing to remote tx nodes.")
|
||||||
group.addoption('--version', action="store_true",
|
|
||||||
help="display version information")
|
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
fixoptions(config)
|
fixoptions(config)
|
||||||
setsession(config)
|
setsession(config)
|
||||||
if config.option.version:
|
|
||||||
p = py.path.local(py.__file__).dirpath()
|
|
||||||
print "This is py.test version %s, imported from %s" % (
|
|
||||||
py.__version__, p)
|
|
||||||
sys.exit(0)
|
|
||||||
#xxxloadplugins(config)
|
#xxxloadplugins(config)
|
||||||
|
|
||||||
def fixoptions(config):
|
def fixoptions(config):
|
||||||
|
@ -154,7 +147,7 @@ def test_plugin_specify(testdir):
|
||||||
|
|
||||||
def test_plugin_already_exists(testdir):
|
def test_plugin_already_exists(testdir):
|
||||||
config = testdir.parseconfig("-p", "default")
|
config = testdir.parseconfig("-p", "default")
|
||||||
assert config.option.plugin == ['default']
|
assert config.option.plugins == ['default']
|
||||||
config.pluginmanager.do_configure(config)
|
config.pluginmanager.do_configure(config)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
""" provide version info, conftest/environment config names.
|
||||||
|
"""
|
||||||
|
import py
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def pytest_addoption(parser):
|
||||||
|
group = parser.getgroup('debugconfig')
|
||||||
|
group.addoption("--help-config", action="store_true", dest="helpconfig",
|
||||||
|
help="show available conftest.py and ENV-variable names.")
|
||||||
|
group.addoption('--version', action="store_true",
|
||||||
|
help="display py lib version and import information.")
|
||||||
|
|
||||||
|
def pytest_configure(__multicall__, config):
|
||||||
|
if config.option.version:
|
||||||
|
p = py.path.local(py.__file__).dirpath()
|
||||||
|
sys.stderr.write("This is py.test version %s, imported from %s\n" %
|
||||||
|
(py.__version__, p))
|
||||||
|
sys.exit(0)
|
||||||
|
if not config.option.helpconfig:
|
||||||
|
return
|
||||||
|
__multicall__.execute()
|
||||||
|
options = []
|
||||||
|
for group in config._parser._groups:
|
||||||
|
options.extend(group.options)
|
||||||
|
widths = [0] * 10
|
||||||
|
tw = py.io.TerminalWriter()
|
||||||
|
tw.sep("-")
|
||||||
|
tw.line("%-13s | %-18s | %-25s | %s" %(
|
||||||
|
"cmdline name", "conftest.py name", "ENV-variable name", "help"))
|
||||||
|
tw.sep("-")
|
||||||
|
|
||||||
|
options = [opt for opt in options if opt._long_opts]
|
||||||
|
options.sort(lambda x, y: cmp(x._long_opts, y._long_opts))
|
||||||
|
for opt in options:
|
||||||
|
if not opt._long_opts:
|
||||||
|
continue
|
||||||
|
optstrings = list(opt._long_opts) # + list(opt._short_opts)
|
||||||
|
optstrings = filter(None, optstrings)
|
||||||
|
optstring = "|".join(optstrings)
|
||||||
|
line = "%-13s | %-18s | %-25s | %s" %(
|
||||||
|
optstring,
|
||||||
|
"option_%s" % opt.dest,
|
||||||
|
"PYTEST_OPTION_%s" % opt.dest.upper(),
|
||||||
|
opt.help and opt.help or "",
|
||||||
|
)
|
||||||
|
tw.line(line[:tw.fullwidth])
|
||||||
|
for name, help in conftest_options:
|
||||||
|
line = "%-13s | %-18s | %-25s | %s" %(
|
||||||
|
"",
|
||||||
|
name,
|
||||||
|
"",
|
||||||
|
help,
|
||||||
|
)
|
||||||
|
tw.line(line[:tw.fullwidth])
|
||||||
|
|
||||||
|
tw.sep("-")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
conftest_options = (
|
||||||
|
('pytest_plugins', 'list of plugin names to load'),
|
||||||
|
('collect_ignore', '(relative) paths ignored during collection'),
|
||||||
|
('rsyncdirs', 'to-be-rsynced directories for dist-testing'),
|
||||||
|
)
|
|
@ -1,40 +1,26 @@
|
||||||
"""nose-compatibility plugin: allow to run nose test suites natively.
|
"""nose-compatibility plugin: allow to run nose test suites natively.
|
||||||
|
|
||||||
This is an experimental plugin for allowing to run tests written
|
This is an experimental plugin for allowing to run tests written
|
||||||
in the 'nosetests' style with py.test.
|
in 'nosetests' style with py.test.
|
||||||
nosetests is a popular clone
|
|
||||||
of py.test and thus shares some philosophy. This plugin is an
|
|
||||||
attempt to understand and neutralize differences. It allows to
|
|
||||||
run nosetests' own test suite and a number of other test suites
|
|
||||||
without problems.
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
If you type::
|
type::
|
||||||
|
|
||||||
py.test -p nose
|
py.test # instead of 'nosetests'
|
||||||
|
|
||||||
where you would type ``nosetests``, you can run your nose style tests.
|
and you should be able to run nose style tests. You will of course
|
||||||
You might also try to run without the nose plugin to see where your test
|
get py.test style reporting and its feature set.
|
||||||
suite is incompatible to the default py.test.
|
|
||||||
|
|
||||||
To avoid the need for specifying a command line option you can set an environment
|
Issues?
|
||||||
variable::
|
----------------
|
||||||
|
|
||||||
PYTEST_PLUGINS=nose
|
If you find issues or have suggestions please run::
|
||||||
|
|
||||||
or create a ``conftest.py`` file in your test directory or below::
|
py.test --pastebin=all
|
||||||
|
|
||||||
# conftest.py
|
and send the resulting URL to a some contact channel.
|
||||||
pytest_plugins = "nose",
|
|
||||||
|
|
||||||
If you find issues or have suggestions you may run::
|
|
||||||
|
|
||||||
py.test -p nose --pastebin=all
|
|
||||||
|
|
||||||
to create a URL of a test run session and send it with comments to the issue
|
|
||||||
tracker or mailing list.
|
|
||||||
|
|
||||||
Known issues
|
Known issues
|
||||||
------------------
|
------------------
|
||||||
|
@ -42,6 +28,8 @@ Known issues
|
||||||
- nose-style doctests are not collected and executed correctly,
|
- nose-style doctests are not collected and executed correctly,
|
||||||
also fixtures don't work.
|
also fixtures don't work.
|
||||||
|
|
||||||
|
- no nose-configuration is recognized
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import py
|
import py
|
||||||
import inspect
|
import inspect
|
||||||
|
|
|
@ -8,7 +8,7 @@ Usage
|
||||||
|
|
||||||
py.test --pastebin=failed
|
py.test --pastebin=failed
|
||||||
|
|
||||||
This will submit full failure information to a remote Paste service and
|
This will submit test run information to a remote Paste service and
|
||||||
provide a URL for each failure. You may select tests as usual or add
|
provide a URL for each failure. You may select tests as usual or add
|
||||||
for example ``-x`` if you only want to send one particular failure.
|
for example ``-x`` if you only want to send one particular failure.
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import py
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
group = parser.getgroup("test process debugging")
|
group = parser.getgroup("debugconfig")
|
||||||
group.addoption('--collectonly',
|
group.addoption('--collectonly',
|
||||||
action="store_true", dest="collectonly",
|
action="store_true", dest="collectonly",
|
||||||
help="only collect tests, don't execute them."),
|
help="only collect tests, don't execute them."),
|
||||||
|
@ -181,8 +181,8 @@ class TerminalReporter:
|
||||||
else:
|
else:
|
||||||
# ensure that the path is printed before the
|
# ensure that the path is printed before the
|
||||||
# 1st test of a module starts running
|
# 1st test of a module starts running
|
||||||
fspath, lineno, msg = self._getreportinfo(item)
|
|
||||||
self.write_fspath_result(fspath, "")
|
self.write_fspath_result(self._getfspath(item), "")
|
||||||
|
|
||||||
def pytest__teardown_final_logerror(self, report):
|
def pytest__teardown_final_logerror(self, report):
|
||||||
self.stats.setdefault("error", []).append(report)
|
self.stats.setdefault("error", []).append(report)
|
||||||
|
@ -199,8 +199,7 @@ class TerminalReporter:
|
||||||
markup = {}
|
markup = {}
|
||||||
self.stats.setdefault(cat, []).append(rep)
|
self.stats.setdefault(cat, []).append(rep)
|
||||||
if not self.config.option.verbose:
|
if not self.config.option.verbose:
|
||||||
fspath, lineno, msg = self._getreportinfo(rep.item)
|
self.write_fspath_result(self._getfspath(rep.item), letter)
|
||||||
self.write_fspath_result(fspath, letter)
|
|
||||||
else:
|
else:
|
||||||
line = self._reportinfoline(rep.item)
|
line = self._reportinfoline(rep.item)
|
||||||
if not hasattr(rep, 'node'):
|
if not hasattr(rep, 'node'):
|
||||||
|
@ -229,9 +228,9 @@ class TerminalReporter:
|
||||||
|
|
||||||
verinfo = ".".join(map(str, sys.version_info[:3]))
|
verinfo = ".".join(map(str, sys.version_info[:3]))
|
||||||
msg = "python: platform %s -- Python %s" % (sys.platform, verinfo)
|
msg = "python: platform %s -- Python %s" % (sys.platform, verinfo)
|
||||||
if self.config.option.verbose or self.config.option.debug:
|
if self.config.option.verbose or self.config.option.debug or getattr(self.config.option, 'pastebin', None):
|
||||||
msg += " -- " + str(sys.executable)
|
|
||||||
msg += " -- pytest-%s" % (py.__version__)
|
msg += " -- pytest-%s" % (py.__version__)
|
||||||
|
msg += " -- " + str(sys.executable)
|
||||||
self.write_line(msg)
|
self.write_line(msg)
|
||||||
|
|
||||||
if self.config.option.debug or self.config.option.traceconfig:
|
if self.config.option.debug or self.config.option.traceconfig:
|
||||||
|
@ -288,8 +287,13 @@ class TerminalReporter:
|
||||||
self.write_line("### Watching: %s" %(rootdir,), bold=True)
|
self.write_line("### Watching: %s" %(rootdir,), bold=True)
|
||||||
|
|
||||||
def _reportinfoline(self, item):
|
def _reportinfoline(self, item):
|
||||||
|
collect_fspath = self._getfspath(item)
|
||||||
fspath, lineno, msg = self._getreportinfo(item)
|
fspath, lineno, msg = self._getreportinfo(item)
|
||||||
if fspath:
|
if fspath and fspath != collect_fspath:
|
||||||
|
fspath = "%s <- %s" % (
|
||||||
|
self.curdir.bestrelpath(collect_fspath),
|
||||||
|
self.curdir.bestrelpath(fspath))
|
||||||
|
elif fspath:
|
||||||
fspath = self.curdir.bestrelpath(fspath)
|
fspath = self.curdir.bestrelpath(fspath)
|
||||||
if lineno is not None:
|
if lineno is not None:
|
||||||
lineno += 1
|
lineno += 1
|
||||||
|
@ -298,7 +302,7 @@ class TerminalReporter:
|
||||||
elif fspath and msg:
|
elif fspath and msg:
|
||||||
line = "%(fspath)s: %(msg)s"
|
line = "%(fspath)s: %(msg)s"
|
||||||
elif fspath and lineno:
|
elif fspath and lineno:
|
||||||
line = "%(fspath)s:%(lineno)s"
|
line = "%(fspath)s:%(lineno)s %(extrapath)s"
|
||||||
else:
|
else:
|
||||||
line = "[noreportinfo]"
|
line = "[noreportinfo]"
|
||||||
return line % locals() + " "
|
return line % locals() + " "
|
||||||
|
@ -322,6 +326,13 @@ class TerminalReporter:
|
||||||
item.__reportinfo = reportinfo
|
item.__reportinfo = reportinfo
|
||||||
return reportinfo
|
return reportinfo
|
||||||
|
|
||||||
|
def _getfspath(self, item):
|
||||||
|
try:
|
||||||
|
return item.fspath
|
||||||
|
except AttributeError:
|
||||||
|
fspath, lineno, msg = self._getreportinfo(item)
|
||||||
|
return fspath
|
||||||
|
|
||||||
#
|
#
|
||||||
# summaries for sessionfinish
|
# summaries for sessionfinish
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import py, os, sys
|
import py, os, sys
|
||||||
from py.__.test.plugin.pytest_capture import CaptureManager, ustream
|
from py.__.test.plugin.pytest_capture import CaptureManager, EncodedFile
|
||||||
|
|
||||||
class TestCaptureManager:
|
class TestCaptureManager:
|
||||||
|
|
||||||
def test_configure_per_fspath(self, testdir):
|
def test_configure_per_fspath(self, testdir):
|
||||||
config = testdir.parseconfig(testdir.tmpdir)
|
config = testdir.parseconfig(testdir.tmpdir)
|
||||||
assert config.getvalue("capture") is None
|
assert config.getvalue("capture") is None
|
||||||
|
@ -12,7 +11,7 @@ class TestCaptureManager:
|
||||||
for name in ('no', 'fd', 'sys'):
|
for name in ('no', 'fd', 'sys'):
|
||||||
sub = testdir.tmpdir.mkdir("dir" + name)
|
sub = testdir.tmpdir.mkdir("dir" + name)
|
||||||
sub.ensure("__init__.py")
|
sub.ensure("__init__.py")
|
||||||
sub.join("conftest.py").write('conf_capture = %r' % name)
|
sub.join("conftest.py").write('option_capture = %r' % name)
|
||||||
assert capman._getmethod(config, sub.join("test_hello.py")) == name
|
assert capman._getmethod(config, sub.join("test_hello.py")) == name
|
||||||
|
|
||||||
@py.test.mark.multi(method=['no', 'fd', 'sys'])
|
@py.test.mark.multi(method=['no', 'fd', 'sys'])
|
||||||
|
@ -57,7 +56,7 @@ class TestCaptureManager:
|
||||||
@py.test.mark.multi(method=['fd', 'sys'])
|
@py.test.mark.multi(method=['fd', 'sys'])
|
||||||
def test_capturing_unicode(testdir, method):
|
def test_capturing_unicode(testdir, method):
|
||||||
testdir.makepyfile("""
|
testdir.makepyfile("""
|
||||||
# taken from issue 227 from nosests
|
# taken from issue 227 from nosetests
|
||||||
def test_unicode():
|
def test_unicode():
|
||||||
import sys
|
import sys
|
||||||
print sys.stdout
|
print sys.stdout
|
||||||
|
@ -68,14 +67,27 @@ def test_capturing_unicode(testdir, method):
|
||||||
"*1 passed*"
|
"*1 passed*"
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_ustream_helper(testdir):
|
@py.test.mark.multi(method=['fd', 'sys'])
|
||||||
|
def test_capturing_bytes_in_utf8_encoding(testdir, method):
|
||||||
|
testdir.makepyfile("""
|
||||||
|
def test_unicode():
|
||||||
|
print '\\xe2'
|
||||||
|
""")
|
||||||
|
result = testdir.runpytest("--capture=%s" % method)
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
"*1 passed*"
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_UnicodeFile(testdir):
|
||||||
p = testdir.makepyfile("hello")
|
p = testdir.makepyfile("hello")
|
||||||
f = p.open('w')
|
f = p.open('w')
|
||||||
#f.encoding = "utf8"
|
pf = EncodedFile(f, "UTF-8")
|
||||||
x = ustream(f)
|
pf.write(u'b\\00f6y\n')
|
||||||
x.write(u'b\\00f6y')
|
pf.write('b\\00f6y\n')
|
||||||
x.close()
|
pf.close()
|
||||||
|
assert f.closed
|
||||||
|
lines = p.readlines()
|
||||||
|
assert lines[0] == lines[1]
|
||||||
|
|
||||||
def test_collect_capturing(testdir):
|
def test_collect_capturing(testdir):
|
||||||
p = testdir.makepyfile("""
|
p = testdir.makepyfile("""
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import py, os
|
||||||
|
|
||||||
|
def test_version(testdir):
|
||||||
|
assert py.version == py.__version__
|
||||||
|
result = testdir.runpytest("--version")
|
||||||
|
assert result.ret == 0
|
||||||
|
p = py.path.local(py.__file__).dirpath()
|
||||||
|
assert result.stderr.fnmatch_lines([
|
||||||
|
'*py.test*%s*imported from*%s*' % (py.version, p)
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_helpconfig(testdir):
|
||||||
|
result = testdir.runpytest("--help-config")
|
||||||
|
assert result.ret == 0
|
||||||
|
assert result.stdout.fnmatch_lines([
|
||||||
|
"*cmdline*conftest*ENV*",
|
||||||
|
])
|
||||||
|
|
|
@ -209,10 +209,6 @@ class TestTerminal:
|
||||||
item = testdir.getitem("def test_func(): pass")
|
item = testdir.getitem("def test_func(): pass")
|
||||||
tr = TerminalReporter(item.config, file=linecomp.stringio)
|
tr = TerminalReporter(item.config, file=linecomp.stringio)
|
||||||
item.config.pluginmanager.register(tr)
|
item.config.pluginmanager.register(tr)
|
||||||
tr.config.hook.pytest_itemstart(item=item)
|
|
||||||
linecomp.assert_contains_lines([
|
|
||||||
"*ABCDE "
|
|
||||||
])
|
|
||||||
tr.config.option.verbose = True
|
tr.config.option.verbose = True
|
||||||
tr.config.hook.pytest_itemstart(item=item)
|
tr.config.hook.pytest_itemstart(item=item)
|
||||||
linecomp.assert_contains_lines([
|
linecomp.assert_contains_lines([
|
||||||
|
@ -227,16 +223,35 @@ class TestTerminal:
|
||||||
item.config.pluginmanager.register(Plugin())
|
item.config.pluginmanager.register(Plugin())
|
||||||
tr = TerminalReporter(item.config, file=linecomp.stringio)
|
tr = TerminalReporter(item.config, file=linecomp.stringio)
|
||||||
item.config.pluginmanager.register(tr)
|
item.config.pluginmanager.register(tr)
|
||||||
tr.config.hook.pytest_itemstart(item=item)
|
|
||||||
linecomp.assert_contains_lines([
|
|
||||||
"*FGHJ "
|
|
||||||
])
|
|
||||||
tr.config.option.verbose = True
|
tr.config.option.verbose = True
|
||||||
tr.config.hook.pytest_itemstart(item=item)
|
tr.config.hook.pytest_itemstart(item=item)
|
||||||
linecomp.assert_contains_lines([
|
linecomp.assert_contains_lines([
|
||||||
"*FGHJ:43: custom*"
|
"*FGHJ:43: custom*"
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_itemreport_subclasses_show_subclassed_file(self, testdir):
|
||||||
|
p1 = testdir.makepyfile(test_p1="""
|
||||||
|
class BaseTests:
|
||||||
|
def test_p1(self):
|
||||||
|
pass
|
||||||
|
class TestClass(BaseTests):
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
p2 = testdir.makepyfile(test_p2="""
|
||||||
|
from test_p1 import BaseTests
|
||||||
|
class TestMore(BaseTests):
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
result = testdir.runpytest(p2)
|
||||||
|
assert result.stdout.fnmatch_lines([
|
||||||
|
"*test_p2.py .",
|
||||||
|
"*1 passed*",
|
||||||
|
])
|
||||||
|
result = testdir.runpytest("-v", p2)
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
"*test_p2.py <- *test_p1.py:2: TestMore.test_p1*",
|
||||||
|
])
|
||||||
|
|
||||||
def test_keyboard_interrupt_dist(self, testdir, option):
|
def test_keyboard_interrupt_dist(self, testdir, option):
|
||||||
p = testdir.makepyfile("""
|
p = testdir.makepyfile("""
|
||||||
raise KeyboardInterrupt
|
raise KeyboardInterrupt
|
||||||
|
|
|
@ -233,8 +233,7 @@ def importplugin(importspec):
|
||||||
|
|
||||||
def isgenerichook(name):
|
def isgenerichook(name):
|
||||||
return name == "pytest_plugins" or \
|
return name == "pytest_plugins" or \
|
||||||
name.startswith("pytest_funcarg__") or \
|
name.startswith("pytest_funcarg__")
|
||||||
name.startswith("pytest_option_")
|
|
||||||
|
|
||||||
def getargs(func):
|
def getargs(func):
|
||||||
args = py.std.inspect.getargs(func.func_code)[0]
|
args = py.std.inspect.getargs(func.func_code)[0]
|
||||||
|
|
|
@ -1,16 +1,6 @@
|
||||||
import py
|
import py
|
||||||
|
|
||||||
EXPECTTIMEOUT=10.0
|
|
||||||
|
|
||||||
class TestGeneralUsage:
|
class TestGeneralUsage:
|
||||||
def test_version(self, testdir):
|
|
||||||
assert py.version == py.__version__
|
|
||||||
result = testdir.runpytest("--version")
|
|
||||||
assert result.ret == 0
|
|
||||||
p = py.path.local(py.__file__).dirpath()
|
|
||||||
assert result.stderr.fnmatch_lines([
|
|
||||||
'*py.test*%s*, imported from: %s*' % (py.version, p)
|
|
||||||
])
|
|
||||||
def test_config_error(self, testdir):
|
def test_config_error(self, testdir):
|
||||||
testdir.makeconftest("""
|
testdir.makeconftest("""
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
|
|
|
@ -42,7 +42,7 @@ class TestConfigCmdlineParsing:
|
||||||
|
|
||||||
def test_parser_addoption_default_conftest(self, testdir, monkeypatch):
|
def test_parser_addoption_default_conftest(self, testdir, monkeypatch):
|
||||||
import os
|
import os
|
||||||
testdir.makeconftest("pytest_option_verbose=True")
|
testdir.makeconftest("option_verbose=True")
|
||||||
config = testdir.parseconfig()
|
config = testdir.parseconfig()
|
||||||
assert config.option.verbose
|
assert config.option.verbose
|
||||||
|
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -105,8 +105,6 @@ def main():
|
||||||
'py.xmlobj.testing'],
|
'py.xmlobj.testing'],
|
||||||
package_data={'py': ['LICENSE',
|
package_data={'py': ['LICENSE',
|
||||||
'bin/_findpy.py',
|
'bin/_findpy.py',
|
||||||
'bin/_genscripts.py',
|
|
||||||
'bin/gendoc.py',
|
|
||||||
'bin/py.cleanup',
|
'bin/py.cleanup',
|
||||||
'bin/py.countloc',
|
'bin/py.countloc',
|
||||||
'bin/py.lookup',
|
'bin/py.lookup',
|
||||||
|
|
Loading…
Reference in New Issue