diff --git a/bin-for-dist/makepluginlist.py b/bin-for-dist/makepluginlist.py
index 73a1cba6e..b640c52d7 100644
--- a/bin-for-dist/makepluginlist.py
+++ b/bin-for-dist/makepluginlist.py
@@ -3,28 +3,29 @@ import os, sys
WIDTH = 75
plugins = [
- ('plugins for Python test functions',
- 'skipping figleaf monkeypatch capture recwarn',),
- ('plugins for other testing styles and languages',
- 'oejskit unittest nose django doctest restdoc'),
- ('plugins for generic reporting and failure logging',
- 'pastebin resultlog terminal',),
- ('plugins for generic reporting and failure logging',
- 'pastebin resultlog terminal',),
- ('misc plugins / core functionality',
- 'helpconfig pdb mark hooklog')
+ ('advanced python testing',
+ 'skipping mark pdb figleaf coverage '
+ 'monkeypatch capture recwarn tmpdir',),
+ ('testing domains',
+ 'oejskit django'),
+ ('reporting and failure logging',
+ 'pastebin xmlresult resultlog terminal',),
+ ('other testing conventions',
+ 'unittest nose doctest restdoc'),
+ ('core debugging / help functionality',
+ 'helpconfig hooklog')
#('internal plugins / core functionality',
- # #'pdb keyword hooklog runner execnetcleanup # pytester',
- # 'pdb keyword hooklog runner execnetcleanup' # pytester',
+ # #'runner execnetcleanup # pytester',
+ # 'runner execnetcleanup' # pytester',
#)
]
externals = {
- 'oejskit': "run javascript tests in real life browsers",
- 'django': "support for testing django applications",
-# 'coverage': "support for using Ned's coverage module",
-# 'xmlresult': "support for generating xml reports "
-# "and CruiseControl integration",
+ 'oejskit': "run javascript tests in real life browsers",
+ 'django': "for testing django applications",
+ 'coverage': "for testing with Ned's coverage module ",
+ 'xmlresult': "for generating xml reports "
+ "and CruiseControl integration",
}
def warn(*args):
@@ -136,7 +137,7 @@ class PluginOverview(RestWriter):
docpath = self.target.dirpath(name).new(ext=".txt")
if oneliner is not None:
htmlpath = docpath.new(ext='.html')
- self.para("%s_ %s" %(name, oneliner))
+ self.para("%s_ (3rd) %s" %(name, oneliner))
self.add_internal_link(name, htmlpath)
else:
doc = PluginDoc(docpath)
@@ -212,7 +213,7 @@ class PluginDoc(RestWriter):
# "py/test/plugin/%s" %(hg_changeset, basename)))
self.links.append((basename,
"http://bitbucket.org/hpk42/py-trunk/raw/%s/"
- "_py/test/plugin/%s" %(pyversion, basename)))
+ "py/plugin/%s" %(pyversion, basename)))
self.links.append(('customize', '../customize.html'))
self.links.append(('plugins', 'index.html'))
self.links.append(('get in contact', '../../contact.html'))
diff --git a/contrib/pytest_coverage/__init__.py b/contrib/pytest_coverage/__init__.py
deleted file mode 100644
index 0feb34a17..000000000
--- a/contrib/pytest_coverage/__init__.py
+++ /dev/null
@@ -1,329 +0,0 @@
-"""
-Tested with coverage 2.85 and pygments 1.0
-
-TODO:
- + 'html-output/*,cover' should be deleted
- + credits for coverage
- + credits for pygments
- + 'Install pygments' after ImportError is to less
- + is the way of determining DIR_CSS_RESOURCE ok?
- + write plugin test
- + '.coverage' still exists in py.test execution dir
-"""
-
-import os
-import sys
-import re
-import shutil
-from StringIO import StringIO
-
-import py
-
-try:
- from pygments import highlight
- from pygments.lexers import get_lexer_by_name
- from pygments.formatters import HtmlFormatter
-except ImportError:
- print "Install pygments" # XXX
- sys.exit(0)
-
-
-DIR_CUR = str(py.path.local())
-REPORT_FILE = os.path.join(DIR_CUR, '.coverage')
-DIR_ANNOTATE_OUTPUT = os.path.join(DIR_CUR, '.coverage_annotate')
-COVERAGE_MODULES = set()
-# coverage output parsing
-REG_COVERAGE_SUMMARY = re.compile('([a-z_\.]+) +([0-9]+) +([0-9]+) +([0-9]+%)')
-REG_COVERAGE_SUMMARY_TOTAL = re.compile('(TOTAL) +([0-9]+) +([0-9]+) +([0-9]+%)')
-DEFAULT_COVERAGE_OUTPUT = '.coverage_annotation'
-# HTML output specific
-DIR_CSS_RESOURCE = os.path.dirname(__import__('pytest_coverage').__file__)
-CSS_RESOURCE_FILES = ['header_bg.jpg', 'links.gif']
-
-COVERAGE_TERM_HEADER = "\nCOVERAGE INFORMATION\n" \
- "====================\n"
-HTML_INDEX_HEADER = '''
-
-
- py.test - Coverage Index
-
-
-
-
-
- Module Coverage
-
-
-
- Module |
- Statements |
- Executed |
- Coverage |
-
- '''
-HTML_INDEX_FOOTER = '''
-
-
- '''
-
-
-class CoverageHtmlFormatter(HtmlFormatter):
- """XXX: doc"""
-
- def __init__(self, *args, **kwargs):
- HtmlFormatter.__init__(self,*args, **kwargs)
- self.annotation_infos = kwargs.get('annotation_infos')
-
- def _highlight_lines(self, tokensource):
- """
- XXX: doc
- """
-
- hls = self.hl_lines
- self.annotation_infos = [None] + self.annotation_infos
- hls = [l for l, i in enumerate(self.annotation_infos) if i]
- for i, (t, value) in enumerate(tokensource):
- if t != 1:
- yield t, value
- if i + 1 in hls: # i + 1 because Python indexes start at 0
- if self.annotation_infos[i+1] == "!":
- yield 1, '%s' \
- % value
- elif self.annotation_infos[i+1] == ">":
- yield 1, '%s' \
- % value
- else:
- raise ValueError("HHAHA: %s" % self.annotation_infos[i+1])
- else:
- yield 1, value
-
-
-def _rename_annotation_files(module_list, dir_annotate_output):
- for m in module_list:
- mod_fpath = os.path.basename(m.__file__)
- if mod_fpath.endswith('pyc'):
- mod_fpath = mod_fpath[:-1]
- old = os.path.join(dir_annotate_output, '%s,cover'% mod_fpath)
- new = os.path.join(dir_annotate_output, '%s,cover'% m.__name__)
- if os.path.isfile(old):
- shutil.move(old, new)
- yield new
-
-def _generate_module_coverage(mc_path, anotation_infos, src_lines):
- #XXX: doc
-
- code = "".join(src_lines)
- mc_path = "%s.html" % mc_path
- lexer = get_lexer_by_name("python", stripall=True)
- formatter = CoverageHtmlFormatter(linenos=True, noclasses=True,
- hl_lines=[1], annotation_infos=anotation_infos)
- result = highlight(code, lexer, formatter)
- fp = open(mc_path, 'w')
- fp.write(result)
- fp.close()
-
-def _parse_modulecoverage(mc_fpath):
- #XXX: doc
-
- fd = open(mc_fpath, 'r')
- anotate_infos = []
- src_lines = []
- for line in fd.readlines():
- anotate_info = line[0:2].strip()
- if not anotate_info:
- anotate_info = None
- src_line = line[2:]
- anotate_infos.append(anotate_info)
- src_lines.append(src_line)
- return mc_fpath, anotate_infos, src_lines
-
-def _parse_coverage_summary(fd):
- """Parses coverage summary output."""
-
- if hasattr(fd, 'readlines'):
- fd.seek(0)
- for l in fd.readlines():
- m = REG_COVERAGE_SUMMARY.match(l)
- if m:
- # yield name, stmts, execs, cover
- yield m.group(1), m.group(2), m.group(3), m.group(4)
- else:
- m = REG_COVERAGE_SUMMARY_TOTAL.match(l)
- if m:
- # yield name, stmts, execs, cover
- yield m.group(1), m.group(2), m.group(3), m.group(4)
-
-
-def _get_coverage_index(mod_name, stmts, execs, cover, annotation_dir):
- """
- Generates the index page where are all modulare coverage reports are
- linked.
- """
-
- if mod_name == 'TOTAL':
- return '%s | %s | %s | %s |
\n' % (mod_name, stmts, execs, cover)
- covrep_fpath = os.path.join(annotation_dir, '%s,cover.html' % mod_name)
- assert os.path.isfile(covrep_fpath) == True
- fname = os.path.basename(covrep_fpath)
- modlink = '%s' % (fname, mod_name)
- return '%s | %s | %s | %s |
\n' % (modlink, stmts, execs, cover)
-
-
-class CoveragePlugin:
- def pytest_addoption(self, parser):
- group = parser.addgroup('coverage options')
- group.addoption('-C', action='store_true', default=False,
- dest = 'coverage',
- help=('displays coverage information.'))
- group.addoption('--coverage-html', action='store', default=False,
- dest='coverage_annotation',
- help='path to the coverage HTML output dir.')
- group.addoption('--coverage-css-resourcesdir', action='store',
- default=DIR_CSS_RESOURCE,
- dest='coverage_css_ressourcedir',
- help='path to dir with css-resources (%s) for '
- 'being copied to the HTML output dir.' % \
- ", ".join(CSS_RESOURCE_FILES))
-
- def pytest_configure(self, config):
- if config.getvalue('coverage'):
- try:
- import coverage
- except ImportError:
- raise config.Error("To run use the coverage option you have to install " \
- "Ned Batchelder's coverage: "\
- "http://nedbatchelder.com/code/modules/coverage.html")
- self.coverage = coverage
- self.summary = None
-
- def pytest_terminal_summary(self, terminalreporter):
- if hasattr(self, 'coverage'):
- self.coverage.stop()
- module_list = [sys.modules[mod] for mod in COVERAGE_MODULES]
- module_list.sort()
- summary_fd = StringIO()
- # get coverage reports by module list
- self.coverage.report(module_list, file=summary_fd)
- summary = COVERAGE_TERM_HEADER + summary_fd.getvalue()
- terminalreporter._tw.write(summary)
-
- config = terminalreporter.config
- dir_annotate_output = config.getvalue('coverage_annotation')
- if dir_annotate_output:
- if dir_annotate_output == "":
- dir_annotate_output = DIR_ANNOTATE_OUTPUT
- # create dir
- if os.path.isdir(dir_annotate_output):
- shutil.rmtree(dir_annotate_output)
- os.mkdir(dir_annotate_output)
- # generate annotation text files for later parsing
- self.coverage.annotate(module_list, dir_annotate_output)
- # generate the separate module coverage reports
- for mc_fpath in _rename_annotation_files(module_list, \
- dir_annotate_output):
- # mc_fpath, anotate_infos, src_lines from _parse_do
- _generate_module_coverage(*_parse_modulecoverage(mc_fpath))
- # creating contents for the index pagee for coverage report
- idxpage_html = StringIO()
- idxpage_html.write(HTML_INDEX_HEADER)
- total_sum = None
- for args in _parse_coverage_summary(summary_fd):
- # mod_name, stmts, execs, cover = args
- idxpage_html.write(_get_coverage_index(*args, \
- **dict(annotation_dir=dir_annotate_output)))
- idxpage_html.write(HTML_INDEX_FOOTER)
- idx_fpath = os.path.join(dir_annotate_output, 'index.html')
- idx_fd = open(idx_fpath, 'w')
- idx_fd.write(idxpage_html.getvalue())
- idx_fd.close()
-
- dir_css_resource_dir = config.getvalue('coverage_css_ressourcedir')
- if dir_annotate_output and dir_css_resource_dir != "":
- if not os.path.isdir(dir_css_resource_dir):
- raise config.Error("CSS resource dir not found: '%s'" % \
- dir_css_resource_dir)
- for r in CSS_RESOURCE_FILES:
- src = os.path.join(dir_css_resource_dir, r)
- if os.path.isfile(src):
- dest = os.path.join(dir_annotate_output, r)
- shutil.copy(src, dest)
-
- def pytest_collectstart(self, collector):
- if isinstance(collector, py.__.test.pycollect.Module):
- COVERAGE_MODULES.update(getattr(collector.obj,
- 'COVERAGE_MODULES', []))
-
- def pytest_testrunstart(self):
- print "self.coverage", self.coverage
- if hasattr(self, 'coverage'):
- print "START coverage"
- self.coverage.erase()
- self.coverage.start()
-
-
diff --git a/contrib/pytest_coverage/header_bg.jpg b/contrib/pytest_coverage/header_bg.jpg
deleted file mode 100644
index ba3513468..000000000
Binary files a/contrib/pytest_coverage/header_bg.jpg and /dev/null differ
diff --git a/contrib/pytest_coverage/links.gif b/contrib/pytest_coverage/links.gif
deleted file mode 100644
index e160f23b6..000000000
Binary files a/contrib/pytest_coverage/links.gif and /dev/null differ
diff --git a/doc/announce/release-1.1.0.txt b/doc/announce/release-1.1.0.txt
new file mode 100644
index 000000000..01a0b7b5a
--- /dev/null
+++ b/doc/announce/release-1.1.0.txt
@@ -0,0 +1,115 @@
+py.test/pylib 1.1.0: Python3, Jython, advanced skipping, cleanups ...
+--------------------------------------------------------------------------------
+
+Features:
+
+* compatible to Python3 (single py2/py3 source), works with Distribute
+* generalized marking_: mark tests one a whole-class or whole-module basis
+* conditional skipping_: skip/xfail based on platform/dependencies
+
+Fixes:
+
+* code reduction and "de-magification" (e.g. 23 KLoc -> 11 KLOC)
+* distribute testing requires the now separately released 'execnet' package
+* funcarg-setup/caching, "same-name" test modules now cause an exlicit error
+* de-cluttered reporting, --report option for skipped/xfail details
+
+Compatibilities
+
+1.1.0 should allow running test code that already worked well with 1.0.2
+plus some more due to improved unittest/nose compatibility.
+
+More information:
+
+ http://pytest.org
+
+thanks and have fun,
+
+holger (http://twitter.com/hpk42)
+
+.. _marking: ../test/plugin/mark.html
+.. _skipping: ../test/plugin/skipping.html
+
+
+Changelog 1.0.2 -> 1.1.0
+-----------------------------------------------------------------------
+
+* remove py.rest tool and internal namespace - it was
+ never really advertised and can still be used with
+ the old release if needed. If there is interest
+ it could be revived into its own tool i guess.
+
+* fix issue48 and issue59: raise an Error if the module
+ from an imported test file does not seem to come from
+ the filepath - avoids "same-name" confusion that has
+ been reported repeatedly
+
+* merged Ronny's nose-compatibility hacks: now
+ nose-style setup_module() and setup() functions are
+ supported
+
+* introduce generalized py.test.mark function marking
+
+* reshuffle / refine command line grouping
+
+* deprecate parser.addgroup in favour of getgroup which creates option group
+
+* add --report command line option that allows to control showing of skipped/xfailed sections
+
+* generalized skipping: a new way to mark python functions with skipif or xfail
+ at function, class and modules level based on platform or sys-module attributes.
+
+* extend py.test.mark decorator to allow for positional args
+
+* introduce and test "py.cleanup -d" to remove empty directories
+
+* fix issue #59 - robustify unittest test collection
+
+* make bpython/help interaction work by adding an __all__ attribute
+ to ApiModule, cleanup initpkg
+
+* use MIT license for pylib, add some contributors
+
+* remove py.execnet code and substitute all usages with 'execnet' proper
+
+* fix issue50 - cached_setup now caches more to expectations
+ for test functions with multiple arguments.
+
+* merge Jarko's fixes, issue #45 and #46
+
+* add the ability to specify a path for py.lookup to search in
+
+* fix a funcarg cached_setup bug probably only occuring
+ in distributed testing and "module" scope with teardown.
+
+* many fixes and changes for making the code base python3 compatible,
+ many thanks to Benjamin Peterson for helping with this.
+
+* consolidate builtins implementation to be compatible with >=2.3,
+ add helpers to ease keeping 2 and 3k compatible code
+
+* deprecate py.compat.doctest|subprocess|textwrap|optparse
+
+* deprecate py.magic.autopath, remove py/magic directory
+
+* move pytest assertion handling to py/code and a pytest_assertion
+ plugin, add "--no-assert" option, deprecate py.magic namespaces
+ in favour of (less) py.code ones.
+
+* consolidate and cleanup py/code classes and files
+
+* cleanup py/misc, move tests to bin-for-dist
+
+* introduce delattr/delitem/delenv methods to py.test's monkeypatch funcarg
+
+* consolidate py.log implementation, remove old approach.
+
+* introduce py.io.TextIO and py.io.BytesIO for distinguishing between
+ text/unicode and byte-streams (uses underlying standard lib io.*
+ if available)
+
+* make py.unittest_convert helper script available which converts "unittest.py"
+ style files into the simpler assert/direct-test-classes py.test/nosetests
+ style. The script was written by Laura Creighton.
+
+* simplified internal localpath implementation
diff --git a/doc/announce/releases.txt b/doc/announce/releases.txt
index 16ba55118..309c29bac 100644
--- a/doc/announce/releases.txt
+++ b/doc/announce/releases.txt
@@ -5,10 +5,12 @@ Release notes
Contents:
.. toctree::
- :maxdepth: 1
+ :maxdepth: 2
- announce/release-1.0.2
- announce/release-1.0.1
- announce/release-1.0.0
- announce/release-0.9.2
- announce/release-0.9.0
+.. include: release-1.1.0
+.. include: release-1.0.2
+
+ release-1.0.1
+ release-1.0.0
+ release-0.9.2
+ release-0.9.0
diff --git a/doc/changelog.txt b/doc/changelog.txt
index 4813547fe..fa456042f 100644
--- a/doc/changelog.txt
+++ b/doc/changelog.txt
@@ -1,6 +1,8 @@
-Changes between 1.0.2 and '1.1.0b1'
+Changes between 1.1.0 and 1.0.2
=====================================
+* adjust and improve docs
+
* remove py.rest tool and internal namespace - it was
never really advertised and can still be used with
the old release if needed. If there is interest
@@ -49,6 +51,9 @@ Changes between 1.0.2 and '1.1.0b1'
* fix a funcarg cached_setup bug probably only occuring
in distributed testing and "module" scope with teardown.
+* many fixes and changes for making the code base python3 compatible,
+ many thanks to Benjamin Peterson for helping with this.
+
* consolidate builtins implementation to be compatible with >=2.3,
add helpers to ease keeping 2 and 3k compatible code
diff --git a/doc/code.txt b/doc/code.txt
index 61c3e5593..1fd1eaef7 100644
--- a/doc/code.txt
+++ b/doc/code.txt
@@ -18,7 +18,7 @@ Contents of the library
Every object in the ``py.code`` library wraps a code Python object related
to code objects, source code, frames and tracebacks: the ``py.code.Code``
class wraps code objects, ``py.code.Source`` source snippets,
-``py.code.Traceback` exception tracebacks, :api:`py.code.Frame`` frame
+``py.code.Traceback` exception tracebacks, ``py.code.Frame`` frame
objects (as found in e.g. tracebacks) and ``py.code.ExceptionInfo`` the
tuple provided by sys.exc_info() (containing exception and traceback
information when an exception occurs). Also in the library is a helper function
diff --git a/doc/confrest.py b/doc/confrest.py
index 6fae19128..953840041 100644
--- a/doc/confrest.py
+++ b/doc/confrest.py
@@ -1,6 +1,6 @@
import py
-from _py.test.plugin.pytest_restdoc import convert_rest_html, strip_html_header
+from py.plugin.pytest_restdoc import convert_rest_html, strip_html_header
html = py.xml.html
@@ -57,23 +57,23 @@ pageTracker._trackPageview();
def fill_menubar(self):
items = [
- self.a_docref("install", "install.html"),
- self.a_docref("contact", "contact.html"),
- self.a_docref("changelog", "changelog.html"),
- self.a_docref("faq", "faq.html"),
+ self.a_docref("INSTALL", "install.html"),
+ self.a_docref("CONTACT", "contact.html"),
+ self.a_docref("CHANGELOG", "changelog.html"),
+ self.a_docref("FAQ", "faq.html"),
html.div(
html.h3("py.test:"),
- self.a_docref("doc index", "test/index.html"),
- self.a_docref("features", "test/features.html"),
- self.a_docref("quickstart", "test/quickstart.html"),
- self.a_docref("tutorials", "test/talks.html"),
- self.a_docref("plugins", "test/plugin/index.html"),
- self.a_docref("funcargs", "test/funcargs.html"),
- self.a_docref("customize", "test/customize.html"),
+ self.a_docref("Index", "test/index.html"),
+ self.a_docref("Quickstart", "test/quickstart.html"),
+ self.a_docref("Features", "test/features.html"),
+ self.a_docref("Plugins", "test/plugin/index.html"),
+ self.a_docref("Funcargs", "test/funcargs.html"),
+ self.a_docref("Customize", "test/customize.html"),
+ self.a_docref("Tutorials", "test/talks.html"),
),
html.div(
html.h3("supporting APIs:"),
- self.a_docref("pylib index", "index.html"),
+ self.a_docref("Index", "index.html"),
self.a_docref("py.path", "path.html"),
self.a_docref("py.code", "code.html"),
)
@@ -85,9 +85,10 @@ pageTracker._trackPageview();
self.menubar = html.div(id=css.menubar, *[
html.div(item) for item in items])
version = py.version
+ announcelink = self.a_docref("%s ANN" % version,
+ "announce/release-%s.html" %(version,))
self.menubar.insert(0,
- html.div("%s" % (py.version), style="font-style: italic;")
- )
+ html.div(announcelink))
#self.a_href("%s-%s" % (self.title, py.version),
# "http://pypi.python.org/pypi/py/%s" % version,
#id="versioninfo",
diff --git a/doc/faq.txt b/doc/faq.txt
index 633ddf756..7705cad6b 100644
--- a/doc/faq.txt
+++ b/doc/faq.txt
@@ -13,75 +13,79 @@ On naming, nosetests, licensing and magic
Why the ``py`` naming? what is it?
------------------------------------
-Because the name was kind of available and there was the
+Because the name was 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.
+because of TAB-completion under Bash/Shells. If you hit
+``py.`` you'll get a list of available development
+tools that all share the ``py.`` prefix. Another motivation
+was to unify the package ("py.test") and tool filename.
What's py.test's 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
+with py.test-1.1.0 it is ever easier 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
+as a clone of ``py.test`` when py.test was in the ``0.8`` release
cycle so some of the newer features_ introduced with py.test-1.0
-have no counterpart in nose_.
+and py.test-1.1 have no counterpart in nose_.
.. _nose: http://somethingaboutorange.com/mrl/projects/nose/0.11.1/
.. _features: test/features.html
+.. _apipkg: http://pypi.python.org/pypi/apipkg
-What's all this "magic" with py.test?
+
+What's this "magic" with py.test?
----------------------------------------
-"All this magic" usually boils down to two issues:
+issues where people have used the term "magic" in the past:
-* 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.
+* `py/__init__.py`_ uses the apipkg_ mechanism for lazy-importing
+ and full control on what API you get when importing "import py".
-* 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.
+* when an ``assert`` statement fails, py.test re-interprets the expression
+ to show intermediate values if a test fails. If your expression
+ has side effects the intermediate values may not be the same, obfuscating
+ the initial error (this is also explained at the command line if it happens).
+ ``py.test --no-assert`` turns off assert re-intepretation.
+ Sidenote: it is good practise to avoid asserts with side effects.
-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
+.. _`py/__init__.py`: http://bitbucket.org/hpk42/py-trunk/src/trunk/py/__init__.py
-function arguments and parametrized tests
-===============================================
+function arguments, parametrized tests and setup
+====================================================
+
+.. _funcargs: test/funcargs.html
+
+Is using funcarg- versus xUnit-based setup a style question?
+---------------------------------------------------------------
+
+It depends. For simple applications or for people experienced
+with nose_ or unittest-style test setup using `xUnit style setup`_
+make some sense. For larger test suites, parametrized testing
+or setup of complex test resources using funcargs_ is recommended.
+Moreover, funcargs are ideal for writing advanced test support
+code (like e.g. the monkeypatch_, the tmpdir_ or capture_ funcargs)
+because the support code can register setup/teardown functions
+in a managed class/module/function scope.
+
+.. _monkeypatch: test/plugin/monkeypatch.html
+.. _tmpdir: test/plugin/tmpdir.html
+.. _capture: test/plugin/capture.html
+.. _`xUnit style setup`: test/xunit_setup.html
+.. _`pytest_nose`: test/plugin/nose.html
.. _`why pytest_pyfuncarg__ methods?`:
@@ -94,7 +98,7 @@ 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. It helps to alleviate the de-coupling of function
argument usage and creation.
.. _`Convention over Configuration`: http://en.wikipedia.org/wiki/Convention_over_Configuration
diff --git a/doc/index.txt b/doc/index.txt
index 46f720a5f..9336b447c 100644
--- a/doc/index.txt
+++ b/doc/index.txt
@@ -29,7 +29,6 @@ Other (minor) support functionality
For the latest Release, see `PyPI project page`_
-.. _`download and installation`: download.html
.. _`py-dev at codespeak net`: http://codespeak.net/mailman/listinfo/py-dev
.. _`py.log`: log.html
.. _`py.io`: io.html
diff --git a/doc/install.txt b/doc/install.txt
index 8795c332d..8ec1d591a 100644
--- a/doc/install.txt
+++ b/doc/install.txt
@@ -25,7 +25,7 @@ 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,
Windows and OSX, Python versions 2.4, 2.5, 2.6 through to
-the Python3 versions 3.0 and 3.1. Jython
+the Python3 versions 3.0 and 3.1 and Jython
.. _mercurial: http://mercurial.selenic.com/wiki/
.. _`Distribute`:
@@ -43,15 +43,13 @@ and documentation source with mercurial_::
hg clone https://bitbucket.org/hpk42/py-trunk/
-This currrently contains a 1.0.x branch and the
-default 'trunk' branch where mainline development
-takes place.
+Development usually takes place on the 'trunk' branch.
.. There also is a readonly subversion
checkout available which contains the latest release::
svn co https://codespeak.net/svn/py/dist
-You can go to the python package index and
+You can also go to the python package index and
download and unpack a TAR file::
http://pypi.python.org/pypi/py/
@@ -64,7 +62,7 @@ With a working `Distribute`_ or setuptools_ installation you can type::
python setup.py develop
-in order to work with the tools and the lib of your checkout.
+in order to work inline with the tools and the lib of your checkout.
.. _`no-setuptools`:
diff --git a/doc/path.txt b/doc/path.txt
index 836317e46..623cd187d 100644
--- a/doc/path.txt
+++ b/doc/path.txt
@@ -40,7 +40,7 @@ a ``py.path.local`` object for us (which wraps a directory):
>>> foofile.read(1)
'b'
-``py.path.svnurl` and :api:`py.path.svnwc``
+``py.path.svnurl` and ``py.path.svnwc``
----------------------------------------------
Two other ``py.path`` implementations that the py lib provides wrap the
diff --git a/doc/test/dist.txt b/doc/test/dist.txt
index 6b44cd69b..8bc83aa7f 100644
--- a/doc/test/dist.txt
+++ b/doc/test/dist.txt
@@ -14,6 +14,8 @@ specify different Python versions and interpreters.
**Requirements**: you need to install the `execnet`_ package
to perform distributed test runs.
+**NOTE**: Version 1.1.0 is not able to distribute tests across Python3/Python2 barriers.
+
Speed up test runs by sending tests to multiple CPUs
----------------------------------------------------------
diff --git a/doc/test/features.txt b/doc/test/features.txt
index 466d515fe..da72fb7ac 100644
--- a/doc/test/features.txt
+++ b/doc/test/features.txt
@@ -26,7 +26,7 @@ naming patterns. As ``py.test`` operates as a separate
cmdline tool you can easily have a command line utility and
some tests in the same file.
-supports many testing practises and methods
+supports several testing practises and methods
==================================================================
py.test supports many testing methods conventionally used in
diff --git a/doc/test/funcargs.txt b/doc/test/funcargs.txt
index 82e993d14..407162c57 100644
--- a/doc/test/funcargs.txt
+++ b/doc/test/funcargs.txt
@@ -1,43 +1,301 @@
-==========================================================
-**funcargs**: test function arguments FTW
-==========================================================
+==============================================================
+**funcargs**: advanced test setup and parametrization
+==============================================================
.. contents::
:local:
:depth: 2
-Goals of the "funcarg" mechanism
-==========================================
+what are "funcargs" and what are they good for?
+=================================================
-Since version 1.0 py.test features the "funcarg" mechanism which
-allows a Python test function to take arguments independently provided
-by factory functions. Factory functions allow to encapsulate
-all setup and fixture glue code into nicely separated objects
-and provide a natural way for writing python test functions.
-Compared to `xUnit style`_ the new mechanism is meant to:
-
-* make test functions easier to write and to read
-* isolate test fixture creation to a single place
-* bring new flexibility and power to test state management
-* naturally extend towards parametrizing test functions
- with multiple argument sets
-* enable creation of zero-boilerplate test helper objects that
- interact with the execution of a test function, see the
- `blog post about the monkeypatch funcarg`_.
-
-If you find issues or have further suggestions for improving
-the mechanism you are welcome to checkout `contact possibilities`_ page.
+Named parameters of a test function are called *funcargs* for short.
+A Funcarg can be a simple number of a complex object. To perform a
+test function call each parameter is setup by a factory function.
+To call a test function repeatedly with different funcargs sets
+test parameters can be generated.
.. _`contact possibilities`: ../contact.html
+.. _`parametrizing tests, generalized`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/
.. _`blog post about the monkeypatch funcarg`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/
.. _`xUnit style`: xunit_setup.html
+
+.. _`funcarg factory`:
+.. _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 factory 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 was called with a ``myfuncarg`` value
+of ``42`` and the assert fails accordingly. Here is how py.test
+calls the 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
+ 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, you'll see an error
+with a list of available function arguments.
+
+factory functions receive a `request object`_
+which they can use to register setup/teardown
+functions or access meta data about a test.
+
+.. _`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 requested argument name, 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.
+
+
+
.. _`tutorial examples`:
Tutorial Examples
=======================================
+To see how you can implement custom paramtrization schemes,
+see e.g. `parametrizing tests, generalized`_ (blog post).
+
+To enable creation of test support code that can flexibly
+register setup/teardown functions see the `blog post about
+the monkeypatch funcarg`_.
+
+If you find issues or have further suggestions for improving
+the mechanism you are welcome to checkout `contact possibilities`_ page.
.. _`application setup tutorial example`:
.. _appsetup:
@@ -274,262 +532,3 @@ methods in a convenient way.
.. _`py.path.local`: ../path.html#local
.. _`conftest plugin`: customize.html#conftestplugin
-
-.. _`funcarg factory`:
-.. _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 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 requested argument name, 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.
-
-
-
diff --git a/doc/test/plugin/coverage.txt b/doc/test/plugin/coverage.txt
new file mode 100644
index 000000000..fcdaa2bb5
--- /dev/null
+++ b/doc/test/plugin/coverage.txt
@@ -0,0 +1,10 @@
+pytest_xmlresult plugin (EXTERNAL)
+==========================================
+
+This plugin allows to write results in an XML format
+compatible to CruiseControl_, see here for download:
+
+ http://github.com/rozza/py.test-plugins
+
+.. _CruiseControl: http://cruisecontrol.sourceforge.net/
+
diff --git a/doc/test/plugin/index.txt b/doc/test/plugin/index.txt
index 38978498c..385f927a0 100644
--- a/doc/test/plugin/index.txt
+++ b/doc/test/plugin/index.txt
@@ -1,63 +1,63 @@
-plugins for Python test functions
-=================================
+advanced python testing
+=======================
skipping_ advanced skipping for python test functions, classes or modules.
+mark_ generic mechanism for marking python functions.
+
+pdb_ interactive debugging with the Python Debugger.
+
figleaf_ write and report coverage data with 'figleaf'.
+coverage_ (3rd) for testing with Ned's coverage module
+
monkeypatch_ safely patch object attributes, dicts and environment variables.
capture_ configurable per-test stdout/stderr capturing mechanisms.
recwarn_ helpers for asserting deprecation and other warnings.
+tmpdir_ provide temporary directories to test functions.
-plugins for other testing styles and languages
-==============================================
-oejskit_ run javascript tests in real life browsers
+testing domains
+===============
+
+oejskit_ (3rd) run javascript tests in real life browsers
+
+django_ (3rd) for testing django applications
+
+
+reporting and failure logging
+=============================
+
+pastebin_ submit failure or test session information to a pastebin service.
+
+xmlresult_ (3rd) for generating xml reports and CruiseControl integration
+
+resultlog_ resultlog plugin for machine-readable logging of test results.
+
+terminal_ Implements terminal reporting of the full testing process.
+
+
+other testing conventions
+=========================
unittest_ automatically discover and run traditional "unittest.py" style tests.
nose_ nose-compatibility plugin: allow to run nose test suites natively.
-django_ support for testing django applications
-
doctest_ collect and execute doctests from modules and test files.
restdoc_ perform ReST syntax, local and remote reference tests on .rst/.txt files.
-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.
-
-
-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
-=================================
+core debugging / help functionality
+===================================
helpconfig_ provide version info, conftest/environment config names.
-pdb_ interactive debugging with the Python Debugger.
-
-mark_ generic mechanism for marking python functions.
-
hooklog_ log invocations of extension hooks to a file.
diff --git a/doc/test/plugin/links.txt b/doc/test/plugin/links.txt
index a4bb73a5f..fb75a2b06 100644
--- a/doc/test/plugin/links.txt
+++ b/doc/test/plugin/links.txt
@@ -1,38 +1,42 @@
.. _`helpconfig`: helpconfig.html
.. _`terminal`: terminal.html
-.. _`pytest_recwarn.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_recwarn.py
+.. _`pytest_recwarn.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_recwarn.py
.. _`unittest`: unittest.html
-.. _`pytest_monkeypatch.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_monkeypatch.py
+.. _`pytest_monkeypatch.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_monkeypatch.py
.. _`pastebin`: pastebin.html
.. _`skipping`: skipping.html
.. _`plugins`: index.html
-.. _`pytest_doctest.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_doctest.py
-.. _`capture`: capture.html
-.. _`pytest_nose.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_nose.py
-.. _`pytest_restdoc.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_restdoc.py
-.. _`restdoc`: restdoc.html
-.. _`pytest_pastebin.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_pastebin.py
.. _`mark`: mark.html
-.. _`pytest_figleaf.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_figleaf.py
-.. _`pytest_hooklog.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_hooklog.py
-.. _`pytest_skipping.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_skipping.py
+.. _`tmpdir`: tmpdir.html
+.. _`pytest_doctest.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_doctest.py
+.. _`capture`: capture.html
+.. _`pytest_nose.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_nose.py
+.. _`pytest_restdoc.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_restdoc.py
+.. _`restdoc`: restdoc.html
+.. _`pytest_pastebin.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_pastebin.py
+.. _`pytest_tmpdir.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_tmpdir.py
+.. _`pytest_figleaf.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_figleaf.py
+.. _`pytest_hooklog.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_hooklog.py
+.. _`pytest_skipping.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_skipping.py
.. _`checkout the py.test development version`: ../../install.html#checkout
-.. _`pytest_helpconfig.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_helpconfig.py
+.. _`pytest_helpconfig.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_helpconfig.py
.. _`oejskit`: oejskit.html
.. _`doctest`: doctest.html
-.. _`pytest_mark.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_mark.py
+.. _`pytest_mark.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_mark.py
.. _`get in contact`: ../../contact.html
-.. _`pytest_capture.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_capture.py
+.. _`pytest_capture.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_capture.py
.. _`figleaf`: figleaf.html
.. _`customize`: ../customize.html
.. _`hooklog`: hooklog.html
-.. _`pytest_terminal.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_terminal.py
+.. _`pytest_terminal.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_terminal.py
.. _`recwarn`: recwarn.html
-.. _`pytest_pdb.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_pdb.py
+.. _`pytest_pdb.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_pdb.py
.. _`monkeypatch`: monkeypatch.html
+.. _`coverage`: coverage.html
.. _`resultlog`: resultlog.html
.. _`django`: django.html
-.. _`pytest_unittest.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_unittest.py
+.. _`xmlresult`: xmlresult.html
+.. _`pytest_unittest.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_unittest.py
.. _`nose`: nose.html
-.. _`pytest_resultlog.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/_py/test/plugin/pytest_resultlog.py
+.. _`pytest_resultlog.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.1.0/py/plugin/pytest_resultlog.py
.. _`pdb`: pdb.html
diff --git a/doc/test/plugin/tmpdir.txt b/doc/test/plugin/tmpdir.txt
new file mode 100644
index 000000000..47514ba75
--- /dev/null
+++ b/doc/test/plugin/tmpdir.txt
@@ -0,0 +1,39 @@
+
+pytest_tmpdir plugin
+====================
+
+provide temporary directories to test functions.
+
+.. contents::
+ :local:
+
+usage example::
+
+ def test_plugin(tmpdir):
+ tmpdir.join("hello").write("hello")
+
+.. _`py.path.local`: ../../path.html
+
+.. _`tmpdir funcarg`:
+
+
+the 'tmpdir' test function argument
+-----------------------------------
+
+return a temporary directory path object
+unique to each test function invocation,
+created as a sub directory of the base temporary
+directory. The returned object is a `py.path.local`_
+path object.
+
+Start improving this plugin in 30 seconds
+=========================================
+
+
+1. Download `pytest_tmpdir.py`_ plugin source code
+2. put it somewhere as ``pytest_tmpdir.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
diff --git a/doc/test/plugin/xmlresult.txt b/doc/test/plugin/xmlresult.txt
new file mode 100644
index 000000000..ec631d4eb
--- /dev/null
+++ b/doc/test/plugin/xmlresult.txt
@@ -0,0 +1,6 @@
+pytest_coverage plugin (EXTERNAL)
+==========================================
+
+This plugin allows to use Ned's coverage package, see
+
+ http://github.com/rozza/py.test-plugins
diff --git a/doc/test/quickstart.txt b/doc/test/quickstart.txt
index ab35fa02d..c4a8005ef 100644
--- a/doc/test/quickstart.txt
+++ b/doc/test/quickstart.txt
@@ -7,7 +7,7 @@ Quickstart
.. _here: ../install.html
-If you have a version of ``easy_install`` (otherwise see here_) just type::
+If you have any ``easy_install`` (otherwise see here_) just type::
easy_install -U py
diff --git a/doc/test/xunit_setup.txt b/doc/test/xunit_setup.txt
index 0a94794cb..a79750c7d 100644
--- a/doc/test/xunit_setup.txt
+++ b/doc/test/xunit_setup.txt
@@ -1,14 +1,20 @@
====================================
-xUnit style setup
+extended xUnit style setup
====================================
.. _`funcargs`: funcargs.html
+.. _`test parametrization`: funcargs.html#parametrizing-tests
+.. _`unittest plugin`: plugin/unittest.html
.. _`xUnit`: http://en.wikipedia.org/wiki/XUnit
Note:
- Since version 1.0 funcargs_ present the recommended way
- to manage flexible and scalable test setups.
+ Since version 1.0 funcargs_ present the new and
+ more powerful way to manage test setups with larger
+ test suites. *funcargs* also provide flexible
+ `test parametrization`_ which goes way beyond
+ what you can do with the xUnit setup/teardown-method
+ patter.
Python, Java and many other languages have a tradition
of using xUnit_ style testing. This typically
@@ -19,6 +25,10 @@ scopes for which you can provide setup/teardown
hooks to provide test fixtures: per-module, per-class
and per-method/function. ``py.test`` will
discover and call according methods automatically.
+
+The `unittest plugin`_ also will intregate ``unittest.TestCase``
+instances into a test run and call respective setup/teardown methods.
+
All setup/teardown methods are optional.
The following methods are called at module level if they exist:
diff --git a/py/__init__.py b/py/__init__.py
index bed2f5ce3..92646bcd1 100644
--- a/py/__init__.py
+++ b/py/__init__.py
@@ -2,20 +2,14 @@
"""
py.test and pylib: rapid testing and development utils
-- `py.test`_: cross-project testing tool with many advanced features
-- `py.path`_: path abstractions over local and subversion files
-- `py.code`_: dynamic code compile and traceback printing support
-
-Compatibility: Linux, Win32, OSX, Python versions 2.4 through to 3.1.
-For questions please check out http://pylib.org/contact.html
-
-.. _`py.test`: http://pylib.org/test.html
-.. _`py.path`: http://pylib.org/path.html
-.. _`py.code`: http://pylib.org/html
+this module uses apipkg.py for lazy-loading sub modules
+and classes. The initpkg-dictionary below specifies
+name->value mappings where value can be another namespace
+dictionary or an import path.
(c) Holger Krekel and others, 2009
"""
-version = "trunk"
+version = "1.1.0"
__version__ = version = version or "1.1.x"
import py.apipkg
diff --git a/py/impl/test/parseopt.py b/py/impl/test/parseopt.py
index 117860af9..b1edf6118 100644
--- a/py/impl/test/parseopt.py
+++ b/py/impl/test/parseopt.py
@@ -46,6 +46,7 @@ class Parser:
self._groups.insert(i+1, group)
return group
+ addgroup = getgroup
def addgroup(self, name, description=""):
py.log._apiwarn("1.1", "use getgroup() which gets-or-creates")
return self.getgroup(name, description)
diff --git a/py/plugin/pytest_default.py b/py/plugin/pytest_default.py
index bc23f7270..ae5540d11 100644
--- a/py/plugin/pytest_default.py
+++ b/py/plugin/pytest_default.py
@@ -70,7 +70,7 @@ def pytest_addoption(parser):
add_dist_options(parser)
else:
parser.epilog = (
- "execnet missing: --looponfailing and distributed testing not available.")
+ "'execnet' package required for --looponfailing / distributed testing.")
def add_dist_options(parser):
# see http://pytest.org/help/dist")
diff --git a/py/plugin/pytest_skipping.py b/py/plugin/pytest_skipping.py
index e733e6b25..ef2fb2cac 100644
--- a/py/plugin/pytest_skipping.py
+++ b/py/plugin/pytest_skipping.py
@@ -83,7 +83,7 @@ skipping on a missing import dependency
--------------------------------------------------
You can use the following import helper at module level
-or within a test or setup function.
+or within a test or test setup function::
docutils = py.test.importorskip("docutils")
diff --git a/py/plugin/pytest_terminal.py b/py/plugin/pytest_terminal.py
index 3b9f243eb..e53f4273d 100644
--- a/py/plugin/pytest_terminal.py
+++ b/py/plugin/pytest_terminal.py
@@ -259,8 +259,8 @@ class TerminalReporter:
verinfo = ".".join(map(str, sys.version_info[:3]))
msg = "python: platform %s -- Python %s" % (sys.platform, verinfo)
+ msg += " -- pytest-%s" % (py.__version__)
if self.config.option.verbose or self.config.option.debug or getattr(self.config.option, 'pastebin', None):
- msg += " -- pytest-%s" % (py.__version__)
msg += " -- " + str(sys.executable)
self.write_line(msg)
diff --git a/py/plugin/pytest_tmpdir.py b/py/plugin/pytest_tmpdir.py
index 74ef36b1d..b442ee009 100644
--- a/py/plugin/pytest_tmpdir.py
+++ b/py/plugin/pytest_tmpdir.py
@@ -1,16 +1,21 @@
-"""
- provide temporary directories to test functions and methods.
+"""provide temporary directories to test functions.
-example:
-
- pytest_plugins = "pytest_tmpdir"
+usage example::
def test_plugin(tmpdir):
tmpdir.join("hello").write("hello")
+.. _`py.path.local`: ../../path.html
+
"""
import py
def pytest_funcarg__tmpdir(request):
+ """return a temporary directory path object
+ unique to each test function invocation,
+ created as a sub directory of the base temporary
+ directory. The returned object is a `py.path.local`_
+ path object.
+ """
name = request.function.__name__
return request.config.mktemp(name, numbered=True)
diff --git a/setup.py b/setup.py
index 0793da9a5..7cb24260a 100644
--- a/setup.py
+++ b/setup.py
@@ -28,7 +28,7 @@ def main():
name='py',
description='py.test and pylib: rapid testing and development utils.',
long_description = long_description,
- version= trunk or '1.1.0b1',
+ version= trunk or '1.1.0',
url='http://pylib.org',
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
@@ -42,7 +42,7 @@ def main():
'py.svnwcrevert = py.cmdline:pysvnwcrevert',
'py.test = py.cmdline:pytest',
'py.which = py.cmdline:pywhich']},
- classifiers=['Development Status :: 4 - Beta',
+ classifiers=['Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: POSIX',
@@ -50,7 +50,6 @@ def main():
'Operating System :: MacOS :: MacOS X',
'Topic :: Software Development :: Testing',
'Topic :: Software Development :: Libraries',
- 'Topic :: System :: Distributed Computing',
'Topic :: Utilities',
'Programming Language :: Python'],
packages=['py',
diff --git a/testing/log/test_log.py b/testing/log/test_log.py
index 85de849ac..69d7675f9 100644
--- a/testing/log/test_log.py
+++ b/testing/log/test_log.py
@@ -118,7 +118,7 @@ class TestLogConsumer:
def test_log_file(self):
customlog = tempdir.join('log.out')
- py.log.setconsumer("default", open(str(customlog), 'w', buffering=0))
+ py.log.setconsumer("default", open(str(customlog), 'w', buffering=1))
py.log.Producer("default")("hello world #1")
assert customlog.readlines() == ['[default] hello world #1\n']