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("pylib index", "index.html"), |             self.a_docref("install", "download.html"), | ||||||
|             self.a_docref("test doc-index", "test/test.html"), |             self.a_docref("contact", "contact.html"), | ||||||
|             self.a_docref("test quickstart", "test/quickstart.html"), |             self.a_docref("faq", "faq.html"), | ||||||
|             self.a_docref("test features", "test/features.html"), |             html.div( | ||||||
|             self.a_docref("test plugins", "test/plugin/index.html"), |                 html.h3("py.test:"), | ||||||
|             self.a_docref("py.execnet", "execnet.html"), |                 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("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