[py-svn] r66995 - in py/dist: . doc doc/announce doc/test doc/test/plugin example/assertion py py/bin py/code py/code/testing py/execnet py/io py/io/testing py/misc/testing py/path/svn py/path/svn/testing py/test py/test/dist py/test/dist/testing py/test/plugin py/test/testing
hpk at codespeak.net
hpk at codespeak.net
Wed Aug 19 18:37:58 CEST 2009
Author: hpk
Date: Wed Aug 19 18:37:53 2009
New Revision: 66995
Added:
py/dist/doc/announce/release-1.0.1.txt
py/dist/doc/faq.txt
py/dist/doc/test/config.html
py/dist/doc/test/customize.txt
py/dist/doc/test/index.txt
py/dist/doc/test/mission.txt
py/dist/doc/test/plugin/helpconfig.txt
py/dist/doc/test/plugin/nose.txt
py/dist/doc/test/talks.txt
py/dist/doc/test/test.html
py/dist/py/misc/testing/test_install.py
py/dist/py/test/plugin/pytest_helpconfig.py
py/dist/py/test/plugin/pytest_nose.py
py/dist/py/test/plugin/test_pytest_helpconfig.py
py/dist/py/test/plugin/test_pytest_nose.py
Removed:
py/dist/doc/test/config.txt
py/dist/doc/test/extend.txt
py/dist/doc/test/test.txt
py/dist/py/bin/_genscripts.py
py/dist/py/bin/gendoc.py
py/dist/py/test/testing/test_install.py
Modified:
py/dist/CHANGELOG
py/dist/MANIFEST
py/dist/doc/bin.txt
py/dist/doc/confrest.py
py/dist/doc/conftest.py
py/dist/doc/contact.txt
py/dist/doc/download.txt
py/dist/doc/index.txt
py/dist/doc/test/attic.txt
py/dist/doc/test/features.txt
py/dist/doc/test/funcargs.txt
py/dist/doc/test/plugin/ (props changed)
py/dist/doc/test/plugin/capture.txt
py/dist/doc/test/plugin/doctest.txt
py/dist/doc/test/plugin/figleaf.txt
py/dist/doc/test/plugin/hooklog.txt
py/dist/doc/test/plugin/hookspec.txt
py/dist/doc/test/plugin/index.txt
py/dist/doc/test/plugin/keyword.txt
py/dist/doc/test/plugin/links.txt
py/dist/doc/test/plugin/monkeypatch.txt
py/dist/doc/test/plugin/pastebin.txt
py/dist/doc/test/plugin/pdb.txt
py/dist/doc/test/plugin/recwarn.txt
py/dist/doc/test/plugin/restdoc.txt
py/dist/doc/test/plugin/resultlog.txt
py/dist/doc/test/plugin/terminal.txt
py/dist/doc/test/plugin/unittest.txt
py/dist/doc/test/plugin/xfail.txt
py/dist/doc/test/quickstart.txt
py/dist/doc/test/xunit_setup.txt
py/dist/doc/xml.txt
py/dist/example/assertion/failure_demo.py
py/dist/example/assertion/test_failures.py
py/dist/py/__init__.py
py/dist/py/_com.py
py/dist/py/code/excinfo.py
py/dist/py/code/testing/test_excinfo.py
py/dist/py/code/testing/test_source.py
py/dist/py/execnet/gateway.py
py/dist/py/execnet/gwmanage.py
py/dist/py/io/stdcapture.py
py/dist/py/io/terminalwriter.py
py/dist/py/io/testing/test_terminalwriter.py
py/dist/py/misc/testing/test_com.py
py/dist/py/path/svn/testing/test_wccommand.py
py/dist/py/path/svn/wccommand.py
py/dist/py/test/collect.py
py/dist/py/test/config.py
py/dist/py/test/defaultconftest.py
py/dist/py/test/dist/dsession.py
py/dist/py/test/dist/testing/acceptance_test.py
py/dist/py/test/dist/txnode.py
py/dist/py/test/plugin/conftest.py
py/dist/py/test/plugin/hookspec.py
py/dist/py/test/plugin/pytest__pytest.py
py/dist/py/test/plugin/pytest_capture.py
py/dist/py/test/plugin/pytest_default.py
py/dist/py/test/plugin/pytest_execnetcleanup.py
py/dist/py/test/plugin/pytest_hooklog.py
py/dist/py/test/plugin/pytest_monkeypatch.py
py/dist/py/test/plugin/pytest_pastebin.py
py/dist/py/test/plugin/pytest_runner.py
py/dist/py/test/plugin/pytest_terminal.py
py/dist/py/test/plugin/pytest_unittest.py
py/dist/py/test/plugin/pytest_xfail.py
py/dist/py/test/plugin/test_pytest_capture.py
py/dist/py/test/plugin/test_pytest_runner.py
py/dist/py/test/plugin/test_pytest_runner_xunit.py
py/dist/py/test/plugin/test_pytest_terminal.py
py/dist/py/test/pluginmanager.py
py/dist/py/test/pycollect.py
py/dist/py/test/testing/acceptance_test.py
py/dist/py/test/testing/test_collect.py
py/dist/py/test/testing/test_config.py
py/dist/py/test/testing/test_pluginmanager.py
py/dist/py/test/testing/test_pycollect.py
py/dist/setup.py
Log:
trying to copy over the 1.0.1 snapshot
Modified: py/dist/CHANGELOG
==============================================================================
--- py/dist/CHANGELOG (original)
+++ py/dist/CHANGELOG Wed Aug 19 18:37:53 2009
@@ -1,3 +1,37 @@
+Changes between 1.0.0 and 1.0.1
+=====================================
+
+* added a 'pytest_nose' plugin which handles nose.SkipTest,
+ nose-style function/method/generator setup/teardown and
+ tries to report functions correctly.
+
+* capturing of unicode writes or encoded strings to sys.stdout/err
+ work better, also terminalwriting 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
+ (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
+
Changes between 1.0.0b9 and 1.0.0
=====================================
Modified: py/dist/MANIFEST
==============================================================================
--- py/dist/MANIFEST (original)
+++ py/dist/MANIFEST Wed Aug 19 18:37:53 2009
@@ -3,9 +3,15 @@
MANIFEST
README.txt
_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.2.txt
doc/announce/release-1.0.0.txt
+doc/announce/release-1.0.1.txt
doc/announce/releases.txt
doc/bin.txt
doc/code.txt
@@ -14,6 +20,7 @@
doc/contact.txt
doc/download.txt
doc/execnet.txt
+doc/faq.txt
doc/img/pylib.png
doc/index.txt
doc/io.txt
@@ -22,21 +29,26 @@
doc/path.txt
doc/style.css
doc/test/attic.txt
-doc/test/config.txt
+doc/test/config.html
+doc/test/customize.txt
doc/test/dist.txt
doc/test/examples.txt
-doc/test/extend.txt
+doc/test/extend.html
doc/test/features.txt
doc/test/funcargs.txt
+doc/test/index.txt
+doc/test/mission.txt
doc/test/plugin/capture.txt
doc/test/plugin/doctest.txt
doc/test/plugin/figleaf.txt
+doc/test/plugin/helpconfig.txt
doc/test/plugin/hooklog.txt
doc/test/plugin/hookspec.txt
doc/test/plugin/index.txt
doc/test/plugin/keyword.txt
doc/test/plugin/links.txt
doc/test/plugin/monkeypatch.txt
+doc/test/plugin/nose.txt
doc/test/plugin/oejskit.txt
doc/test/plugin/pastebin.txt
doc/test/plugin/pdb.txt
@@ -48,7 +60,7 @@
doc/test/plugin/xfail.txt
doc/test/quickstart.txt
doc/test/talks.txt
-doc/test/test.txt
+doc/test/test.html
doc/test/xunit_setup.txt
doc/xml.txt
example/assertion/failure_demo.py
@@ -80,13 +92,10 @@
example/genhtml.py
example/genhtmlcss.py
example/genxml.py
-makepluginlist.py
py/LICENSE
py/__init__.py
py/_com.py
py/bin/_findpy.py
-py/bin/_genscripts.py
-py/bin/gendoc.py
py/bin/py.cleanup
py/bin/py.countloc
py/bin/py.lookup
@@ -239,6 +248,7 @@
py/misc/testing/test_com.py
py/misc/testing/test_error.py
py/misc/testing/test_initpkg.py
+py/misc/testing/test_install.py
py/misc/testing/test_std.py
py/misc/testing/test_svnlook.py
py/misc/testing/test_terminal.py
@@ -342,9 +352,11 @@
py/test/plugin/pytest_doctest.py
py/test/plugin/pytest_execnetcleanup.py
py/test/plugin/pytest_figleaf.py
+py/test/plugin/pytest_helpconfig.py
py/test/plugin/pytest_hooklog.py
py/test/plugin/pytest_keyword.py
py/test/plugin/pytest_monkeypatch.py
+py/test/plugin/pytest_nose.py
py/test/plugin/pytest_pastebin.py
py/test/plugin/pytest_pdb.py
py/test/plugin/pytest_pylint.py
@@ -358,6 +370,8 @@
py/test/plugin/pytest_unittest.py
py/test/plugin/pytest_xfail.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_xunit.py
py/test/plugin/test_pytest_terminal.py
@@ -379,7 +393,6 @@
py/test/testing/test_deprecated_api.py
py/test/testing/test_funcargs.py
py/test/testing/test_genitems.py
-py/test/testing/test_install.py
py/test/testing/test_outcome.py
py/test/testing/test_parseopt.py
py/test/testing/test_pickling.py
Added: py/dist/doc/announce/release-1.0.1.txt
==============================================================================
--- (empty file)
+++ py/dist/doc/announce/release-1.0.1.txt Wed Aug 19 18:37:53 2009
@@ -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
Modified: py/dist/doc/bin.txt
==============================================================================
--- py/dist/doc/bin.txt (original)
+++ py/dist/doc/bin.txt Wed Aug 19 18:37:53 2009
@@ -15,7 +15,7 @@
The ``py.test`` executable is the main entry point into the py-lib testing tool,
see the `py.test documentation`_.
-.. _`py.test documentation`: test/test.html
+.. _`py.test documentation`: test/index.html
``py.cleanup``
==============
@@ -51,6 +51,7 @@
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
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
Modified: py/dist/doc/confrest.py
==============================================================================
--- py/dist/doc/confrest.py (original)
+++ py/dist/doc/confrest.py Wed Aug 19 18:37:53 2009
@@ -45,9 +45,9 @@
def a_docref(self, name, relhtmlpath):
docpath = self.project.docpath
- return html.a(name, class_="menu",
+ return html.div(html.a(name, class_="menu",
href=relpath(self.targetpath.strpath,
- docpath.join(relhtmlpath).strpath))
+ docpath.join(relhtmlpath).strpath)))
def a_apigenref(self, name, relhtmlpath):
apipath = self.project.apigenpath
@@ -57,19 +57,30 @@
def fill_menubar(self):
items = [
- self.a_docref("pylib index", "index.html"),
- self.a_docref("test doc-index", "test/test.html"),
- self.a_docref("test quickstart", "test/quickstart.html"),
- self.a_docref("test features", "test/features.html"),
- self.a_docref("test plugins", "test/plugin/index.html"),
- self.a_docref("py.execnet", "execnet.html"),
+ self.a_docref("install", "download.html"),
+ self.a_docref("contact", "contact.html"),
+ self.a_docref("faq", "faq.html"),
+ html.div(
+ html.h3("py.test:"),
+ self.a_docref("doc index", "test/index.html"),
+ self.a_docref("features", "test/features.html"),
+ self.a_docref("quickstart", "test/quickstart.html"),
+ self.a_docref("tutorials", "test/talks.html"),
+ self.a_docref("plugins", "test/plugin/index.html"),
+ self.a_docref("funcargs", "test/funcargs.html"),
+ self.a_docref("customize", "test/customize.html"),
+ ),
+ html.div(
+ html.h3("supporting APIs:"),
+ self.a_docref("pylib index", "index.html"),
+ self.a_docref("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_apigenref("api", "api/index.html"),
#self.a_apigenref("source", "source/index.html"),
#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, *[
html.div(item) for item in items])
Modified: py/dist/doc/conftest.py
==============================================================================
--- py/dist/doc/conftest.py (original)
+++ py/dist/doc/conftest.py Wed Aug 19 18:37:53 2009
@@ -3,3 +3,5 @@
#py.test.importorskip("pygments")
pytest_plugins = ['pytest_restdoc']
rsyncdirs = ['.']
+
+collect_ignore = ['test/attic.txt']
Modified: py/dist/doc/contact.txt
==============================================================================
--- py/dist/doc/contact.txt (original)
+++ py/dist/doc/contact.txt Wed Aug 19 18:37:53 2009
@@ -5,9 +5,12 @@
- #pylib on irc.freenode.net IRC channel for random questions.
+
- `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
bugs or request features.
@@ -22,6 +25,8 @@
.. _tetamap: http://tetamap.wordpress.com
+.. _`@pylibcommit`: http://twitter.com/pylibcommit
+
..
get an account on codespeak
@@ -33,14 +38,13 @@
you are new to the python developer community please come to the IRC
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
.. _us: http://codespeak.net/mailman/listinfo/py-dev
.. _codespeak: http://codespeak.net/
.. _`py-dev`:
.. _`development mailing list`:
.. _`py-dev developers list`: http://codespeak.net/mailman/listinfo/py-dev
-.. _`subversion commit mailing list`:
.. _`py-svn`:
-.. _`py-svn general commit mailing list`: http://codespeak.net/mailman/listinfo/py-svn
-.. _`development bug/feature tracker`: https://codespeak.net/issue/py-dev/
+.. _`commit mailing list`: http://codespeak.net/mailman/listinfo/py-svn
Modified: py/dist/doc/download.txt
==============================================================================
--- py/dist/doc/download.txt (original)
+++ py/dist/doc/download.txt Wed Aug 19 18:37:53 2009
@@ -7,7 +7,7 @@
Latest Release, see `PyPI project page`_
-using setuptools / easy_install
+using easy_install
===================================================
With a working `setuptools installation`_ you can type::
@@ -16,16 +16,11 @@
to get the latest release of the py lib. The ``-U`` switch
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,
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
0.8 versions of the py lib on your system, please download
and execute http://codespeak.net/svn/py/build/winpathclean.py
@@ -36,9 +31,11 @@
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
@@ -47,41 +44,59 @@
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::
- python setup.py develop
+ svn co https://codespeak.net/svn/py/dist
-in order to work with your checkout version.
+You can also go to the python package index and
+download and unpack a TAR file::
-For enhancing one of the plugins you may go to
-the ``py/test/plugin/`` sub directory.
+ http://pypi.python.org/pypi/py/
-.. _mercurial: http://mercurial.selenic.com/wiki/
+activating checkout with setuptools
+--------------------------------------------
+
+With a working `setuptools installation`_ you can issue::
+
+ python setup.py develop
+
+in order to work with the tools and the lib of your checkout.
.. _`no-setuptools`:
-Working without setuptools / from source
-==========================================
+activating a checkout or tarball without setuptools
+-------------------------------------------------------------
+
+To import the py lib the ``py`` package directory needs to
+be on the ``$PYTHONPATH``. If you exexute scripts directly
+from ``py/bin/`` or ``py\bin\win32`` they will find their
+containing py lib automatically.
-If you have a checkout_ or a tarball_ it is actually not neccessary to issue
-``setup.py`` commands in order to use py lib and its tools. You can
-simply add the root directory to ``PYTHONPATH`` and ``py/bin`` or
-``py\bin\win32`` to your ``PATH`` settings.
+It is usually a good idea to add the parent directory of the ``py`` package
+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:
-There are also helper scripts to set the environment
-on windows::
+on windows execute::
+ # inside autoexec.bat or shell startup
c:\\path\to\checkout\py\env.cmd
-and on linux/osx you can add something like this to
-your shell initialization::
+on linux/OSX add this to your shell initialization::
- eval `python ~/path/to/checkout/py/env.py`
+ # inside .bashrc
+ eval `python ~/path/to/checkout/py/env.py`
both of which which will get you good settings
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::
mypkg/
@@ -90,39 +105,26 @@
tests/
py/
-then issuing ``py.test subpkg1`` will use the py lib
-from that projects root directory.
+issuing ``py.test subpkg1`` will use the py lib
+from that projects root directory.
+
+.. _`command line scripts`: bin.html
Debian and RPM packages
===================================
-As of July 2009 pytest/pylib 1.0 RPMs and Debian packages
-are not yet available. So you will only find older
-versions.
-
-On Debian systems look for ``python-codespeak-lib``.
-*But this package is probably outdated - if somebody
-can help with bringing this up to date,
-that would be very much appreciated.*
+As of August 2009 pytest/pylib 1.0 RPMs and Debian packages
+are not available. You will only find 0.9 versions -
+on Debian systems look for ``python-codespeak-lib``
+and Dwayne Bailey has put together a Fedora `RPM`_.
+
+If you can help with providing/upgrading distribution
+packages please use of the contact_ channels in case
+of questions or need for changes.
-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
.. _`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
-
Added: py/dist/doc/faq.txt
==============================================================================
--- (empty file)
+++ py/dist/doc/faq.txt Wed Aug 19 18:37:53 2009
@@ -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/
+
+
Modified: py/dist/doc/index.txt
==============================================================================
--- py/dist/doc/index.txt (original)
+++ py/dist/doc/index.txt Wed Aug 19 18:37:53 2009
@@ -38,7 +38,7 @@
.. _`py.io`: io.html
.. _`py.path`: path.html
.. _`py.code`: code.html
-.. _`py.test`: test/test.html
+.. _`py.test`: test/index.html
.. _`py lib scripts`: bin.html
.. _`py.xml`: xml.html
.. _`miscellaneous features`: misc.html
Modified: py/dist/doc/test/attic.txt
==============================================================================
--- py/dist/doc/test/attic.txt (original)
+++ py/dist/doc/test/attic.txt Wed Aug 19 18:37:53 2009
@@ -72,3 +72,46 @@
.. _`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):
+ ...
Added: py/dist/doc/test/config.html
==============================================================================
--- (empty file)
+++ py/dist/doc/test/config.html Wed Aug 19 18:37:53 2009
@@ -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>
+
Deleted: /py/dist/doc/test/config.txt
==============================================================================
--- /py/dist/doc/test/config.txt Wed Aug 19 18:37:53 2009
+++ (empty file)
@@ -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
Added: py/dist/doc/test/customize.txt
==============================================================================
--- (empty file)
+++ py/dist/doc/test/customize.txt Wed Aug 19 18:37:53 2009
@@ -0,0 +1,421 @@
+================================================
+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`:
+
+project specific "local" or named "global" plugins
+--------------------------------------------------------------
+
+py.test implements much of its functionality by calling `well specified
+hooks`_. Python modules which contain such hook functions are called
+plugins. Hook functions are discovered in ``conftest.py`` files or in
+`named plugins`_. ``conftest.py`` files are sometimes called
+"anonymous" or conftest plugins. They are useful for keeping test
+extensions close to your application. Named plugins are normal python
+modules or packages that can be distributed separately. Named plugins
+need to follow a naming pattern; they have an all lowercase ``pytest_``
+prefixed name. While conftest plugins are discovered automatically,
+named plugins must be explicitely specified.
+
+.. _`named plugins`: plugin/index.html
+
+.. _`tool startup`:
+.. _`loaded at tool startup`:
+.. _`test tool starts up`:
+
+Plugin discovery at tool startup
+--------------------------------------------
+
+py.test loads plugin modules at tool startup in the following way:
+
+* by reading the ``PYTEST_PLUGINS`` environment variable
+ and importing the comma-separated list of named plugins.
+
+* by pre-scanning the command line for the ``-p name`` option
+ and loading the specified plugin before actual command line parsing.
+
+* by loading all `conftest.py plugin`_ files as inferred by the command line
+ invocation
+
+* by recursively loading all plugins specified by the
+ ``pytest_plugins`` variable in a ``conftest.py`` file
+
+Note that at tool startup only ``conftest.py`` files in
+the directory of the specified test modules (or the current dir if None)
+or any of the parent directories are found. There is no try to
+pre-scan all subdirectories to find ``conftest.py`` files or test
+modules.
+
+Specifying plugins in a test module or plugin
+-----------------------------------------------
+
+You can specify plugins in a test module or a plugin like this:
+
+.. sourcecode:: python
+
+ pytest_plugins = "name1", "name2",
+
+When the test module or plugin is loaded the specified plugins
+will be loaded. If you specify plugins without the ``pytest_``
+prefix it will be automatically added. All plugin names
+must be lowercase.
+
+.. _`conftest.py plugin`:
+.. _`conftestplugin`:
+
+conftest.py as anonymous per-project plugins
+--------------------------------------------------
+
+The purpose of ``conftest.py`` files is to allow `project-specific
+test configuration`_. They thus make for a good place to implement
+project-specific test related features through hooks. For example you may
+set the `collect_ignore`_ variable depending on a command line option
+by defining the following hook in a ``conftest.py`` file:
+
+.. _`exclude-file-example`:
+
+.. sourcecode:: python
+
+ # ./conftest.py in your root or package dir
+ collect_ignore = ['hello', 'test_world.py']
+ def pytest_addoption(parser):
+ parser.addoption("--runall", action="store_true", default=False)
+ def pytest_configure(config):
+ if config.getvalue("runall"):
+ collect_ignore[:] = []
+
+
+.. _`well specified hooks`:
+.. _`implement hooks`:
+
+Important py.test hooks
+====================================
+
+py.test calls hooks functions to implement its `test collection`_,
+running and reporting process. When py.test loads a plugin it validates
+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
+to accept *less* parameters. You'll get useful errors on mistyped hook or
+argument names. Read on for some introductory information on particular
+hooks. It's sensible to look at existing plugins so see example usages
+and start off with your own plugin.
+
+.. _`hook definition specification`: plugin/hookspec.html
+
+.. _`configuration hooks`:
+
+command line parsing and configuration hooks
+--------------------------------------------------------------------
+
+When the `test tool starts up`_ it will invoke all hooks that add
+command line options in the python standard optparse style.
+
+.. sourcecode:: python
+
+ def pytest_addoption(parser):
+ """ add command line options. """"
+ parser.addoption("--myopt", dest="myopt", action="store_true")
+
+After all these hooks have been called, the command line is parser
+and a ``config`` object is created and another hook is invoked,
+for example:
+
+.. sourcecode:: python
+
+ def pytest_configure(config):
+ config.getvalue("myopt")
+
+When the test run finishes this corresponding finalizer hook is called:
+
+ def pytest_unconfigure(config):
+ ...
+
+
+adding global py.test helpers and functionality
+--------------------------------------------------------------------
+
+If you want to make global helper functions or objects available
+to your test code you can implement:
+
+ def pytest_namespace():
+ """ return dictionary with items to be made available on py.test. namespace """
+
+All such returned items will be made available directly on
+the ``py.test`` namespace.
+
+If you want to provide helpers that are specific to a test function run or need
+to be setup per test function run, please refer to the `funcargs mechanism`_.
+
+.. _`funcargs mechanism`: funcargs.html
+
+
+generic "runtest" hooks
+------------------------------
+
+Each test item is usually executed by calling the following three hooks:
+
+.. sourcecode:: python
+
+ pytest_runtest_setup(item)
+ pytest_runtest_call(item)
+ pytest_runtest_teardown(item)
+
+For each of the three invocations a `call object`_ encapsulates
+information about the outcome of the call and is subsequently used
+to make a report object:
+
+.. sourcecode:: python
+
+ report = hook.pytest_runtest_makereport(item, call)
+
+For example, the `pytest_pdb plugin`_ uses this hook to activate
+interactive debugging on failures when ``--pdb`` is specified on the
+command line.
+
+Usually three reports will be generated for a single test item for each
+of the three runtest hooks respectively. If ``pytest_runtest_setup``
+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:
+
+.. sourcecode:: python
+
+ pytest_runtest_logreport(report)
+
+A ``report`` object contains status and reporting information:
+
+.. sourcecode:: python
+
+ report.longrepr = string/lines/object to print
+ report.when = "setup", "call" or "teardown"
+ report.shortrepr = letter for progress-report
+ report.passed = True or False
+ report.failed = True or False
+ report.skipped = True or False
+
+The `pytest_terminal plugin`_ uses this hook to print information
+about a test run.
+
+The whole protocol described here is implemented via this hook:
+
+.. sourcecode:: python
+
+ pytest_runtest_protocol(item) -> True
+
+.. _`call object`:
+
+The call object contains information about a performed call:
+
+.. sourcecode:: python
+
+ call.excinfo = ExceptionInfo object or None
+ call.when = "setup", "call" or "teardown"
+ call.outerr = None or tuple of strings representing captured stdout/stderr
+
+.. _`pytest_pdb plugin`: http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/pytest_pdb.py
+.. _`pytest_terminal plugin`: http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/pytest_terminal.py
+
+
+generic collection hooks
+------------------------------
+
+py.test calls the following two fundamental hooks for collecting files and directories:
+
+.. sourcecode:: python
+
+ def pytest_collect_directory(path, parent):
+ """ return Collection node or None for the given path. """
+
+ def pytest_collect_file(path, parent):
+ """ return Collection node or None for the given path. """
+
+Both return a `collection node`_ for a given path. All returned
+nodes from all hook implementations will participate in the
+collection and running protocol. The ``parent`` object is
+the parent node and may be used to access command line
+options via the ``parent.config`` object.
+
+
+Python test function and module hooks
+----------------------------------------------------
+
+For influencing the collection of objects in Python modules
+you can use the following hook:
+
+.. sourcecode:: python
+
+ def pytest_pycollect_makeitem(collector, name, obj):
+ """ return custom item/collector for a python object in a module, or None. """
+
+This hook will be called for each Python object in a collected
+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.
+
+
+.. _`collection process`:
+.. _`collection node`:
+.. _`test collection`:
+
+
+Test Collection process
+======================================================
+
+the collection tree
+---------------------------------
+
+The collecting process is iterative so that distribution
+and execution of tests can start as soon as the first test
+item is collected. Collection nodes with children are
+called "Collectors" and terminal nodes are called "Items".
+Here is an example of such a tree, generated with the
+command ``py.test --collectonly py/xmlobj``::
+
+ <Directory 'xmlobj'>
+ <Directory 'testing'>
+ <Module 'test_html.py' (py.__.xmlobj.testing.test_html)>
+ <Function 'test_html_name_stickyness'>
+ <Function 'test_stylenames'>
+ <Function 'test_class_None'>
+ <Function 'test_alternating_style'>
+ <Module 'test_xml.py' (py.__.xmlobj.testing.test_xml)>
+ <Function 'test_tag_with_text'>
+ <Function 'test_class_identity'>
+ <Function 'test_tag_with_text_and_attributes'>
+ <Function 'test_tag_with_subclassed_attr_simple'>
+ <Function 'test_tag_nested'>
+ <Function 'test_tag_xmlname'>
+
+By default all directories not starting with a dot are traversed,
+looking for ``test_*.py`` and ``*_test.py`` files. Those Python
+files are imported under their `package name`_.
+
+The Module collector looks for test functions
+and test classes and methods. Test functions and methods
+are prefixed ``test`` by default. Test classes must
+start with a capitalized ``Test`` prefix.
+
+.. _`package name`:
+
+constructing the package name for test modules
+-------------------------------------------------
+
+Test modules are imported under their fully qualified
+name. Given a filesystem ``fspath`` it is constructed as follows:
+
+* walk the directories up to the last one that contains
+ an ``__init__.py`` file.
+
+* perform ``sys.path.insert(0, basedir)``.
+
+* import the root package as ``root``
+
+* determine the fully qualified name for ``fspath`` by either:
+
+ * calling ``root.__pkg__.getimportname(fspath)`` if the
+ ``__pkg__`` exists.` or
+
+ * otherwise use the relative path of the module path to
+ the base dir and turn slashes into dots and strike
+ the trailing ``.py``.
+
Deleted: /py/dist/doc/test/extend.txt
==============================================================================
--- /py/dist/doc/test/extend.txt Wed Aug 19 18:37:53 2009
+++ (empty file)
@@ -1,329 +0,0 @@
-================================================
-Extending and customizing py.test
-================================================
-
-.. _`local plugin`:
-
-py.test implements much of its functionality by calling `well specified
-hooks`_. Python modules which contain such hook functions are called
-plugins. Hook functions are discovered in ``conftest.py`` files or in
-`named plugins`_. ``conftest.py`` files are sometimes called
-"anonymous" or conftest plugins. They are useful for keeping test
-extensions close to your application. Named plugins are normal python
-modules or packages that can be distributed separately. Named plugins
-need to follow a naming pattern; they have an all lowercase ``pytest_``
-prefixed name. While conftest plugins are discovered automatically,
-named plugins must be explicitely specified.
-
-.. _`named plugins`: plugin/index.html
-
-.. _`tool startup`:
-.. _`test tool starts up`:
-
-Plugin discovery at tool startup
---------------------------------------------
-
-py.test loads plugin modules at tool startup in the following way:
-
-* by reading the ``PYTEST_PLUGINS`` environment variable
- and importing the comma-separated list of named plugins.
-
-* by pre-scanning the command line for the ``-p name`` option
- and loading the specified plugin before actual command line parsing.
-
-* by loading all `conftest.py plugin`_ files as inferred by the command line
- invocation
-
-* by recursively loading all plugins specified by the
- ``pytest_plugins`` variable in a ``conftest.py`` file
-
-Note that at tool startup only ``conftest.py`` files in
-the directory of the specified test modules (or the current dir if None)
-or any of the parent directories are found. There is no try to
-pre-scan all subdirectories to find ``conftest.py`` files or test
-modules.
-
-Specifying plugins in a test module or plugin
------------------------------------------------
-
-You can specify plugins in a test module or a plugin like this:
-
-.. sourcecode:: python
-
- pytest_plugins = "name1", "name2",
-
-When the test module or plugin is loaded the specified plugins
-will be loaded. If you specify plugins without the ``pytest_``
-prefix it will be automatically added. All plugin names
-must be lowercase.
-
-.. _`conftest.py plugin`:
-.. _`conftestplugin`:
-
-conftest.py as anonymous per-project plugins
---------------------------------------------------
-
-The purpose of ``conftest.py`` files is to allow `project-specific
-test configuration`_. They thus make for a good place to implement
-project-specific test related features through hooks. For example you may
-set the `collect_ignore`_ variable depending on a command line option
-by defining the following hook in a ``conftest.py`` file:
-
-.. _`exclude-file-example`:
-
-.. sourcecode:: python
-
- # ./conftest.py in your root or package dir
- collect_ignore = ['hello', 'test_world.py']
- def pytest_addoption(parser):
- parser.addoption("--runall", action="store_true", default=False)
- def pytest_configure(config):
- if config.getvalue("runall"):
- collect_ignore[:] = []
-
-.. _`project-specific test configuration`: config.html#conftestpy
-.. _`collect_ignore`: config.html#collectignore
-
-.. _`well specified hooks`:
-
-Available py.test hooks
-====================================
-
-py.test calls hooks functions to implement its `test collection`_, running and
-reporting process. Upon loading of a plugin py.test performs
-strict checking on contained hook functions. Function and argument names
-need to match exactly one of `hook definition specification`_. It thus
-provides useful error reporting on mistyped hook or argument names
-and minimizes version incompatibilites. Below you find some introductory
-information on particular hooks. It's sensible to look at existing
-plugins so see example usages and start off with your own plugin.
-
-.. _`hook definition specification`: plugin/hookspec.html
-
-.. _`configuration hooks`:
-
-command line parsing and configuration hooks
---------------------------------------------------------------------
-
-When the `test tool starts up`_ it will invoke all hooks that add
-command line options in the python standard optparse style.
-
-.. sourcecode:: python
-
- def pytest_addoption(parser):
- """ add command line options. """"
- parser.addoption("--myopt", dest="myopt", action="store_true")
-
-After all these hooks have been called, the command line is parser
-and a ``config`` object is created and another hook is invoked,
-for example:
-
-.. sourcecode:: python
-
- def pytest_configure(config):
- config.getvalue("myopt")
-
-When the test run finishes this corresponding finalizer hook is called:
-
- def pytest_unconfigure(config):
- ...
-
-
-adding global py.test helpers and functionality
---------------------------------------------------------------------
-
-If you want to make global helper functions or objects available
-to your test code you can implement:
-
- def pytest_namespace():
- """ return dictionary with items to be made available on py.test. namespace """
-
-All such returned items will be made available directly on
-the ``py.test`` namespace.
-
-If you want to provide helpers that are specific to a test function run or need
-to be setup per test function run, please refer to the `funcargs mechanism`_.
-
-.. _`funcargs mechanism`: funcargs.html
-
-
-generic "runtest" hooks
-------------------------------
-
-Each test item is usually executed by calling the following three hooks:
-
-.. sourcecode:: python
-
- pytest_runtest_setup(item)
- pytest_runtest_call(item)
- pytest_runtest_teardown(item)
-
-For each of the three invocations a `call object`_ encapsulates
-information about the outcome of the call and is subsequently used
-to make a report object:
-
-.. sourcecode:: python
-
- report = hook.pytest_runtest_makereport(item, call)
-
-For example, the `pytest_pdb plugin`_ uses this hook to activate
-interactive debugging on failures when ``--pdb`` is specified on the
-command line.
-
-Usually three reports will be generated for a single test item. However,
-if the ``pytest_runtest_setup`` fails no call or teardown hooks
-will be called and only one report will be created.
-
-Each of the up to three reports is eventually fed to the logreport hook:
-
-.. sourcecode:: python
-
- pytest_runtest_logreport(report)
-
-A ``report`` object contains status and reporting information:
-
-.. sourcecode:: python
-
- report.longrepr = string/lines/object to print
- report.when = "setup", "call" or "teardown"
- report.shortrepr = letter for progress-report
- report.passed = True or False
- report.failed = True or False
- report.skipped = True or False
-
-The `pytest_terminal plugin`_ uses this hook to print information
-about a test run.
-
-The protocol described here is implemented via this hook:
-
-.. sourcecode:: python
-
- pytest_runtest_protocol(item) -> True
-
-.. _`call object`:
-
-The call object contains information about a performed call:
-
-.. sourcecode:: python
-
- call.excinfo = ExceptionInfo object or None
- call.when = "setup", "call" or "teardown"
- call.outerr = None or tuple of strings representing captured stdout/stderr
-
-.. _`pytest_pdb plugin`: http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/pytest_pdb.py
-.. _`pytest_terminal plugin`: http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/pytest_terminal.py
-
-
-generic collection hooks
-------------------------------
-
-py.test calls the following two fundamental hooks for collecting files and directories:
-
-.. sourcecode:: python
-
- def pytest_collect_directory(path, parent):
- """ return Collection node or None for the given path. """
-
- def pytest_collect_file(path, parent):
- """ return Collection node or None for the given path. """
-
-Both return a `collection node`_ for a given path. All returned
-nodes from all hook implementations will participate in the
-collection and running protocol. The ``parent`` object is
-the parent node and may be used to access command line
-options via the ``parent.config`` object.
-
-
-Python test function and module hooks
-----------------------------------------------------
-
-For influencing the collection of objects in Python modules
-you can use the following hook:
-
-.. sourcecode:: python
-
- def pytest_pycollect_makeitem(collector, name, obj):
- """ return custom item/collector for a python object in a module, or None. """
-
-This hook will be called for each Python object in a collected
-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.
-
-
-
-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 node`:
-.. _`test collection`:
-
-
-Test Collection process
-======================================================
-
-The collecting process is iterative so that distribution
-and execution of tests can start as soon as the first test
-item is collected. Collection nodes with children are
-called "Collectors" and terminal nodes are called "Items".
-Here is an example of such a tree, generated with the
-command ``py.test --collectonly py/xmlobj``::
-
- <Directory 'xmlobj'>
- <Directory 'testing'>
- <Module 'test_html.py' (py.__.xmlobj.testing.test_html)>
- <Function 'test_html_name_stickyness'>
- <Function 'test_stylenames'>
- <Function 'test_class_None'>
- <Function 'test_alternating_style'>
- <Module 'test_xml.py' (py.__.xmlobj.testing.test_xml)>
- <Function 'test_tag_with_text'>
- <Function 'test_class_identity'>
- <Function 'test_tag_with_text_and_attributes'>
- <Function 'test_tag_with_subclassed_attr_simple'>
- <Function 'test_tag_nested'>
- <Function 'test_tag_xmlname'>
-
-By default all directories not starting with a dot are traversed,
-looking for ``test_*.py`` and ``*_test.py`` files. Those Python
-files are imported under their `package name`_.
-
-The Module collector looks for test functions
-and test classes and methods. Test functions and methods
-are prefixed ``test`` by default. Test classes must
-start with a capitalized ``Test`` prefix.
-
-.. _`package name`:
-
-constructing the package name for test modules
--------------------------------------------------
-
-Test modules are imported under their fully qualified
-name. Given a filesystem ``fspath`` it is constructed as follows:
-
-* walk the directories up to the last one that contains
- an ``__init__.py`` file.
-
-* perform ``sys.path.insert(0, basedir)``.
-
-* import the root package as ``root``
-
-* determine the fully qualified name for ``fspath`` by either:
-
- * calling ``root.__pkg__.getimportname(fspath)`` if the
- ``__pkg__`` exists.` or
-
- * otherwise use the relative path of the module path to
- the base dir and turn slashes into dots and strike
- the trailing ``.py``.
-
Modified: py/dist/doc/test/features.txt
==============================================================================
--- py/dist/doc/test/features.txt (original)
+++ py/dist/doc/test/features.txt Wed Aug 19 18:37:53 2009
@@ -1,117 +1,77 @@
==================================================
-py.test features
+py.test feature overview
==================================================
-py.test is an extensible tool for running all kinds
-of tests on one or more machines. It supports a variety
-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
+.. contents::
+ :local:
: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`:
automatically collects and executes tests
===============================================
-py.test discovers tests automatically by inspecting specified
-directories or files. By default, it collects all python
-modules with a leading ``test_`` or trailing ``_test`` filename.
-From each test module every function with a leading ``test_``
-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.
+py.test discovers tests automatically by looking at
+specified directories and its files for common
+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.
-.. _`ad-hoc run your test on multiple platforms one a single test run`: dist.html#atonce
+supports many testing practises and methods
+==================================================================
-extensive debugging support
-===================================
+py.test supports many testing methods conventionally used in
+the Python community. It runs traditional `unittest.py`_,
+`doctest.py`_, supports `xUnit style setup`_ and nose_ specific
+setups and test suites. It offers minimal no-boilerplate model
+for configuring and deploying tests written as simple Python
+functions or methods. It also integrates `coverage testing
+with figleaf`_ or `Javasript unit- and functional testing`_.
-testing starts immediately
---------------------------
+.. _`Javasript unit- and functional testing`: plugin/oejskit.html
+.. _`coverage testing with figleaf`: plugin/figleaf.html
-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.
+no-boilerplate test functions with Python
+===================================================
-support for modules containing tests
---------------------------------------
+automatic Python test discovery
+------------------------------------
-As ``py.test`` operates as a separate cmdline
-tool you can easily have a command line utility and
-some tests in the same file.
+By default, all python modules with a ``test_*.py``
+filename are inspected for finding tests:
-debug with the ``print`` statement
-----------------------------------
+* functions with a name beginning with ``test_``
+* classes with a leading ``Test`` name and ``test`` prefixed methods.
+* ``unittest.TestCase`` subclasses
+
+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.
-By default, ``py.test`` catches text written to stdout/stderr during
-the execution of each individual test. This output will only be
-displayed however if the test fails; you will not see it
-otherwise. 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.
-
-Each failing test that produced output during the running of the test
-function will have its output displayed in the ``recorded stdout`` section.
-
-During Setup and Teardown ("Fixture") capturing is performed separately so
-that you will only see this output if the actual fixture functions fail.
-
-The catching of stdout/stderr output can be disabled using the
-``--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
---------------------------------
-
-Tests usually run in the order in which they appear in the files.
-However, tests should not rely on running one after another, as
-this prevents more advanced usages: running tests
-distributedly or selectively, or in "looponfailing" mode,
-will cause them to run in random order.
+.. _captured: plugin/capture.html
assert with the ``assert`` statement
----------------------------------------
@@ -142,79 +102,86 @@
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
provide you with helpful output in case of failures such as *no
exception* or *wrong exception*.
-useful tracebacks, recursion detection
---------------------------------------
-A lot of care is taken to present nice tracebacks in case of test
-failure. Try::
+information-rich tracebacks, PDB introspection
+-------------------------------------------------------
- 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
-failure situation.
+A lot of care is taken to present useful failure information
+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
-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``.
+advanced skipping of tests
+-------------------------------
-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.
+If you want to skip tests you can use ``py.test.skip`` within
+test or setup functions. Example::
-no inheritance requirement
---------------------------
+ def test_hello():
+ if sys.platform != "win32":
+ py.test.skip("only win32 supported")
-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.
+You can also use a helper to skip on a failing import::
-testing for deprecated APIs
-------------------------------
+ docutils = py.test.importorskip("docutils")
-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.
+or to skip if a library does not have the right version::
+ docutils = py.test.importorskip("docutils", minversion="0.3")
-advanced test selection / skipping
-=========================================================
+The version will be read from the specified module's ``__version__`` attribute.
-dynamically skipping tests
--------------------------------
+.. _`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
-If you want to skip tests you can use ``py.test.skip`` within
-test or setup functions. Example::
+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.skip("message")
+ py.test -n 3
-You can also use a helper to skip on a failing import::
+Read more on `distributed testing`_.
- docutils = py.test.importorskip("docutils")
+.. _`distributed testing`: dist.html
-or to skip if a library does not have the right version::
+ad-hoc run tests cross-platform
+==================================================
- docutils = py.test.importorskip("docutils", minversion="0.3")
+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.
-The version will be read from the module's ``__version__`` attribute.
+.. _`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`:
-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
on the command line. Examples::
@@ -246,65 +213,21 @@
.. _`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
=========================================
-Since 1.0 py.test has advanced `extension mechanisms`_
-and a growing `list of plugins`_.
+py.test has advanced `extension mechanisms`_
+with a growing `list of default plugins`_.
One can can easily modify or add aspects for for
purposes such as:
* reporting extensions
* customizing collection and execution of tests
-* running non-python tests
-* managing custom test state setup
+* running and managing non-python tests
+* managing domain-specific test state setup
-.. _`list of plugins`: plugin/index.html
-.. _`extension mechanisms`: extend.html
+.. _`list of default plugins`: plugin/index.html
+.. _`extension mechanisms`: customize.html#extensions
.. _`reStructured Text`: http://docutils.sourceforge.net
.. _`Python debugger`: http://docs.python.org/lib/module-pdb.html
Modified: py/dist/doc/test/funcargs.txt
==============================================================================
--- py/dist/doc/test/funcargs.txt (original)
+++ py/dist/doc/test/funcargs.txt Wed Aug 19 18:37:53 2009
@@ -2,8 +2,15 @@
**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
-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
all setup and fixture glue code into nicely separated objects
and provide a natural way for writing python test functions.
@@ -14,7 +21,6 @@
* bring new flexibility and power to test state management
* naturally extend towards parametrizing test functions
with multiple argument sets
- (superseding `old-style generative tests`_)
* 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`_.
@@ -26,7 +32,248 @@
.. _`blog post about the monkeypatch funcarg`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/
.. _`xUnit style`: xunit_setup.html
-.. _`old-style generative tests`: features.html#generative-tests
+
+.. _`tutorial examples`:
+
+Tutorial Examples
+=======================================
+
+
+.. _`application setup tutorial example`:
+.. _appsetup:
+
+application specific test setup and fixtures
+---------------------------------------------------------
+
+Here is a basic useful step-wise example for handling application
+specific test setup. The goal is to have one place where we have the
+glue and test support code for bootstrapping and configuring application objects and allow
+test modules and test functions to stay ignorant of involved details.
+
+step 1: use and implement a test/app-specific "mysetup"
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Let's write a simple test function living in a test file
+``test_sample.py`` that uses a ``mysetup`` funcarg for accessing test
+specific setup.
+
+.. sourcecode:: python
+
+ # ./test_sample.py
+ def test_answer(mysetup):
+ app = mysetup.myapp()
+ answer = app.question()
+ assert answer == 42
+
+To run this test py.test needs to find and call a factory to
+obtain the required ``mysetup`` function argument. The test
+function interacts with the provided application specific setup.
+
+To provide the ``mysetup`` function argument we write down
+a factory method in a `local plugin`_ by putting the
+following code into a local ``conftest.py``:
+
+.. sourcecode:: python
+
+ # ./conftest.py
+
+ from myapp import MyApp
+
+ def pytest_funcarg__mysetup(request):
+ return MySetup()
+
+ class MySetup:
+ def myapp(self):
+ return MyApp()
+
+To run the example we represent our application by putting a pseudo MyApp object into ``myapp.py``:
+
+.. sourcecode:: python
+
+ # ./myapp.py
+ class MyApp:
+ def question(self):
+ return 6 * 9
+
+You can now run the test with ``py.test test_sample.py`` which will
+show this failure:
+
+.. sourcecode:: python
+
+ ========================= test session starts =========================
+ python: platform linux2 -- Python 2.6.2
+ test object 1: /home/hpk/hg/py/trunk/example/funcarg/mysetup
+
+ test_sample.py F
+
+ ============================== FAILURES ===============================
+ _____________________________ test_answer _____________________________
+
+ mysetup = <mysetup.conftest.MySetup instance at 0xa020eac>
+
+ def test_answer(mysetup):
+ app = mysetup.myapp()
+ answer = app.question()
+ > assert answer == 42
+ E assert 54 == 42
+
+ test_sample.py:5: AssertionError
+ ====================== 1 failed in 0.11 seconds =======================
+
+This means that our ``mysetup`` object was successfully instantiated,
+we asked it to provide an application instance and checking
+its ``question`` method resulted in the wrong answer. If you are
+confused as to what the concrete question or answers actually mean,
+please see here_ :) Otherwise proceed to step 2.
+
+.. _here: http://uncyclopedia.wikia.com/wiki/The_Hitchhiker's_Guide_to_the_Galaxy
+.. _`local plugin`: customize.html#local-plugin
+
+.. _`tut-cmdlineoption`:
+
+step 2: adding a command line option
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+If you provide a "funcarg" from a plugin you can easily make methods
+depend on command line options or environment settings.
+To add a command line option we update the conftest.py of
+the previous example to add a command line option
+and to offer a new mysetup method:
+
+.. sourcecode:: python
+
+ # ./conftest.py
+ import py
+ from myapp import MyApp
+
+ def pytest_funcarg__mysetup(request):
+ return MySetup(request)
+
+ def pytest_addoption(parser):
+ parser.addoption("--ssh", action="store", default=None,
+ help="specify ssh host to run tests with")
+
+
+ class MySetup:
+ def __init__(self, request):
+ self.config = request.config
+
+ def myapp(self):
+ return MyApp()
+
+ def getsshconnection(self):
+ host = self.config.option.ssh
+ if host is None:
+ py.test.skip("specify ssh host with --ssh")
+ return py.execnet.SshGateway(host)
+
+
+Now any test function can use the ``mysetup.getsshconnection()`` method like this:
+
+.. sourcecode:: python
+
+ # ./test_ssh.py
+ class TestClass:
+ def test_function(self, mysetup):
+ conn = mysetup.getsshconnection()
+ # work with conn
+
+Running ``py.test test_ssh.py`` without specifying a command line option will result in a skipped test_function:
+
+.. sourcecode:: python
+
+ ========================= test session starts =========================
+ python: platform linux2 -- Python 2.6.2
+ test object 1: test_ssh.py
+
+ test_ssh.py s
+
+ ________________________ skipped test summary _________________________
+ conftest.py:23: [1] Skipped: 'specify ssh host with --ssh'
+ ====================== 1 skipped in 0.11 seconds ======================
+
+Note especially how the test function could stay clear knowing about how to construct test state values or when to skip and with what message. The test function can concentrate on actual test code and test state factories can interact with execution of tests.
+
+If you specify a command line option like ``py.test --ssh=python.org`` the test will get un-skipped and actually execute.
+
+.. _`accept example`:
+
+example: specifying and selecting acceptance tests
+--------------------------------------------------------------
+
+.. sourcecode:: python
+
+ # ./conftest.py
+ def pytest_option(parser):
+ group = parser.getgroup("myproject")
+ group.addoption("-A", dest="acceptance", action="store_true",
+ help="run (slow) acceptance tests")
+
+ def pytest_funcarg__accept(request):
+ return AcceptFuncarg(request)
+
+ class AcceptFuncarg:
+ def __init__(self, request):
+ if not request.config.option.acceptance:
+ py.test.skip("specify -A to run acceptance tests")
+ self.tmpdir = request.config.mktemp(request.function.__name__, numbered=True)
+
+ def run(self, cmd):
+ """ called by test code to execute an acceptance test. """
+ self.tmpdir.chdir()
+ return py.process.cmdexec(cmd)
+
+
+and the actual test function example:
+
+.. sourcecode:: python
+
+ def test_some_acceptance_aspect(accept):
+ accept.tmpdir.mkdir("somesub")
+ result = accept.run("ls -la")
+ assert "somesub" in result
+
+If you run this test without specifying a command line option
+the test will get skipped with an appropriate message. Otherwise
+you can start to add convenience and test support methods
+to your AcceptFuncarg and drive running of tools or
+applications and provide ways to do assertions about
+the output.
+
+.. _`decorate a funcarg`:
+
+example: decorating a funcarg in a test module
+--------------------------------------------------------------
+
+For larger scale setups it's sometimes useful to decorare
+a funcarg just for a particular test module. We can
+extend the `accept example`_ by putting this in our test module:
+
+.. sourcecode:: python
+
+ def pytest_funcarg__accept(request):
+ # call the next factory (living in our conftest.py)
+ arg = request.getfuncargvalue("accept")
+ # create a special layout in our tempdir
+ arg.tmpdir.mkdir("special")
+ return arg
+
+ class TestSpecialAcceptance:
+ def test_sometest(self, accept):
+ assert accept.tmpdir.join("special").check()
+
+Our module level factory will be invoked first and it can
+ask its request object to call the next factory and then
+decorate its result. This mechanism allows us to stay
+ignorant of how/where the function argument is provided -
+in our example from a `conftest plugin`_.
+
+sidenote: the temporary directory used here are instances of
+the `py.path.local`_ class which provides many of the os.path
+methods in a convenient way.
+
+.. _`py.path.local`: ../path.html#local
+.. _`conftest plugin`: customize.html#conftestplugin
.. _`funcarg factory`:
@@ -51,14 +298,14 @@
.. sourcecode:: python
- ============================ test session starts ============================
+ =========================== 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 _______________________________
+ ================================ FAILURES ==================================
+ ______________________________ test_function _______________________________
myfuncarg = 42
@@ -67,7 +314,7 @@
E assert 42 == 17
test_simplefactory.py:6: AssertionError
- ========================= 1 failed in 0.11 seconds ==========================
+ ======================== 1 failed in 0.11 seconds ==========================
This means that the test function got executed and the assertion failed.
@@ -107,7 +354,7 @@
``request.config``: access to command line opts and general config
-``request.param``: if exists was passed by a `parametrizing test generator`_
+``request.param``: if exists was passed by a previous `metafunc.addcall`_
.. _`useful caching and finalization helpers`:
@@ -181,9 +428,9 @@
exception will be raised.
.. _`test generators`:
-.. _`parametrizing test generator`:
+.. _`parametrizing-tests`:
-generating parametrized tests with funcargs
+generating parametrized tests
===========================================================
You can parametrize multiple runs of the same test
@@ -206,14 +453,14 @@
.. sourcecode:: python
- ================================= test session starts =================================
+ ============================= 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] ________________________________
+ ================================ FAILURES ==================================
+ __________________________ test_func.test_func[9] __________________________
numiter = 9
@@ -253,6 +500,8 @@
``metafunc.config``: access to command line opts and general config
+.. _`metafunc.addcall`:
+
the ``metafunc.addcall()`` method
-----------------------------------------------
@@ -282,263 +531,4 @@
and test setup/run happens in different process.
-.. _`tutorial examples`:
-
-Funcarg Tutorial Examples
-=======================================
-
-
-.. _`application setup tutorial example`:
-
-application specific test setup
----------------------------------------------------------
-
-Here is a basic useful step-wise example for handling application
-specific test setup. The goal is to have one place where we have the
-glue and test support code for bootstrapping and configuring application objects and allow
-test modules and test functions to stay ignorant of involved details.
-
-step 1: use and implement a test/app-specific "mysetup"
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-Let's write a simple test function living in a test file
-``test_sample.py`` that uses a ``mysetup`` funcarg for accessing test
-specific setup.
-
-.. sourcecode:: python
-
- # ./test_sample.py
- def test_answer(mysetup):
- app = mysetup.myapp()
- answer = app.question()
- assert answer == 42
-
-To run this test py.test needs to find and call a factory to
-obtain the required ``mysetup`` function argument. The test
-function interacts with the provided application specific setup.
-
-To provide the ``mysetup`` function argument we write down
-a factory method in a `local plugin`_ by putting the
-following code into a local ``conftest.py``:
-
-.. sourcecode:: python
-
- # ./conftest.py
-
- from myapp import MyApp
-
- def pytest_funcarg__mysetup(request):
- return MySetup()
-
- class MySetup:
- def myapp(self):
- return MyApp()
-
-To run the example we represent our application by putting a pseudo MyApp object into ``myapp.py``:
-
-.. sourcecode:: python
-
- # ./myapp.py
- class MyApp:
- def question(self):
- return 6 * 9
-
-You can now run the test with ``py.test test_sample.py`` which will
-show this failure:
-
-.. sourcecode:: python
-
- ========================= test session starts =========================
- python: platform linux2 -- Python 2.6.2
- test object 1: /home/hpk/hg/py/trunk/example/funcarg/mysetup
-
- test_sample.py F
-
- ============================== FAILURES ===============================
- _____________________________ test_answer _____________________________
-
- mysetup = <mysetup.conftest.MySetup instance at 0xa020eac>
-
- def test_answer(mysetup):
- app = mysetup.myapp()
- answer = app.question()
- > assert answer == 42
- E assert 54 == 42
-
- test_sample.py:5: AssertionError
- ====================== 1 failed in 0.11 seconds =======================
-
-This means that our ``mysetup`` object was successfully instantiated,
-we asked it to provide an application instance and checking
-its ``question`` method resulted in the wrong answer. If you are
-confused as to what the concrete question or answers actually mean,
-please see here_ :) Otherwise proceed to step 2.
-
-.. _here: http://uncyclopedia.wikia.com/wiki/The_Hitchhiker's_Guide_to_the_Galaxy
-.. _`local plugin`: extend.html#local-plugin
-
-
-step 2: adding a command line option
-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-If you provide a "funcarg" from a plugin you can easily make methods
-depend on command line options or environment settings.
-To add a command line option we update the conftest.py of
-the previous example to add a command line option
-and to offer a new mysetup method:
-
-.. sourcecode:: python
-
- # ./conftest.py
- import py
- from myapp import MyApp
-
- def pytest_funcarg__mysetup(request):
- return MySetup(request)
-
- def pytest_addoption(parser):
- parser.addoption("--ssh", action="store", default=None,
- help="specify ssh host to run tests with")
-
-
- class MySetup:
- def __init__(self, request):
- self.config = request.config
-
- def myapp(self):
- return MyApp()
-
- def getsshconnection(self):
- host = self.config.option.ssh
- if host is None:
- py.test.skip("specify ssh host with --ssh")
- return py.execnet.SshGateway(host)
-
-
-Now any test function can use the ``mysetup.getsshconnection()`` method like this:
-
-.. sourcecode:: python
-
- # ./test_ssh.py
- class TestClass:
- def test_function(self, mysetup):
- conn = mysetup.getsshconnection()
- # work with conn
-
-Running ``py.test test_ssh.py`` without specifying a command line option will result in a skipped test_function:
-
-.. sourcecode:: python
-
- ========================= test session starts =========================
- python: platform linux2 -- Python 2.6.2
- test object 1: test_ssh.py
-
- test_ssh.py s
-
- ________________________ skipped test summary _________________________
- conftest.py:23: [1] Skipped: 'specify ssh host with --ssh'
- ====================== 1 skipped in 0.11 seconds ======================
-
-Note especially how the test function could stay clear knowing about how to construct test state values or when to skip and with what message. The test function can concentrate on actual test code and test state factories can interact with execution of tests.
-
-If you specify a command line option like ``py.test --ssh=python.org`` the test will get un-skipped and actually execute.
-
-.. _`accept example`:
-
-example: specifying and selecting acceptance tests
---------------------------------------------------------------
-
-.. sourcecode:: python
-
- # ./conftest.py
- def pytest_option(parser):
- group = parser.getgroup("myproject")
- group.addoption("-A", dest="acceptance", action="store_true",
- help="run (slow) acceptance tests")
-
- def pytest_funcarg__accept(request):
- return AcceptFuncarg(request)
-
- class AcceptFuncarg:
- def __init__(self, request):
- if not request.config.option.acceptance:
- py.test.skip("specify -A to run acceptance tests")
- self.tmpdir = request.config.mktemp(request.function.__name__, numbered=True)
-
- def run(self, cmd):
- """ called by test code to execute an acceptance test. """
- self.tmpdir.chdir()
- return py.process.cmdexec(cmd)
-
-
-and the actual test function example:
-
-.. sourcecode:: python
-
- def test_some_acceptance_aspect(accept):
- accept.tmpdir.mkdir("somesub")
- result = accept.run("ls -la")
- assert "somesub" in result
-
-If you run this test without specifying a command line option
-the test will get skipped with an appropriate message. Otherwise
-you can start to add convenience and test support methods
-to your AcceptFuncarg and drive running of tools or
-applications and provide ways to do assertions about
-the output.
-
-.. _`decorate a funcarg`:
-
-example: decorating a funcarg in a test module
---------------------------------------------------------------
-
-For larger scale setups it's sometimes useful to decorare
-a funcarg just for a particular test module. We can
-extend the `accept example`_ by putting this in our test module:
-
-.. sourcecode:: python
-
- # method of class
- def pytest_funcarg__accept(request):
- # call the next factory in the conftest.py file
- arg = request.getfuncargvalue("accept")
- arg.tmpdir.mkdir("special")
- return arg
-
- class TestSpecialAcceptance:
- def test_sometest(self, accept):
- assert accept.tmpdir.join("special").check()
-
-Our module-level "accept" factory is invoked first and here
-it asks its request object to call the next factory and then
-decorate its result. This mechanism allows us to stay
-ignorant of how/where the function argument is provided -
-in our example from a `conftest plugin`_.
-
-sidenote: the temporary directory used here are instances of
-the `py.path.local`_ class which provides many of the os.path
-methods in a convenient way.
-
-.. _`py.path.local`: ../path.html#local
-.. _`conftest plugin`: extend.html#conftestplugin
-
-
-Questions and Answers
-==================================
-
-.. _`why pytest_pyfuncarg__ methods?`:
-
-Why ``pytest_funcarg__*`` methods?
-------------------------------------
-
-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
Added: py/dist/doc/test/index.txt
==============================================================================
--- (empty file)
+++ py/dist/doc/test/index.txt Wed Aug 19 18:37:53 2009
@@ -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
+
+
Added: py/dist/doc/test/mission.txt
==============================================================================
--- (empty file)
+++ py/dist/doc/test/mission.txt Wed Aug 19 18:37:53 2009
@@ -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
Modified: py/dist/doc/test/plugin/capture.txt
==============================================================================
--- py/dist/doc/test/plugin/capture.txt (original)
+++ py/dist/doc/test/plugin/capture.txt Wed Aug 19 18:37:53 2009
@@ -38,7 +38,7 @@
If you set capturing values in a conftest file like this::
# conftest.py
- conf_capture = 'fd'
+ option_capture = 'fd'
then all tests in that directory will execute with "fd" style capturing.
@@ -120,12 +120,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_capture.py`_ plugin source code
2. put it somewhere as ``pytest_capture.py`` into your import path
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
Modified: py/dist/doc/test/plugin/doctest.txt
==============================================================================
--- py/dist/doc/test/plugin/doctest.txt (original)
+++ py/dist/doc/test/plugin/doctest.txt Wed Aug 19 18:37:53 2009
@@ -29,12 +29,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_doctest.py`_ plugin source code
2. put it somewhere as ``pytest_doctest.py`` into your import path
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
Modified: py/dist/doc/test/plugin/figleaf.txt
==============================================================================
--- py/dist/doc/test/plugin/figleaf.txt (original)
+++ py/dist/doc/test/plugin/figleaf.txt Wed Aug 19 18:37:53 2009
@@ -24,12 +24,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_figleaf.py`_ plugin source code
2. put it somewhere as ``pytest_figleaf.py`` into your import path
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
Added: py/dist/doc/test/plugin/helpconfig.txt
==============================================================================
--- (empty file)
+++ py/dist/doc/test/plugin/helpconfig.txt Wed Aug 19 18:37:53 2009
@@ -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
Modified: py/dist/doc/test/plugin/hooklog.txt
==============================================================================
--- py/dist/doc/test/plugin/hooklog.txt (original)
+++ py/dist/doc/test/plugin/hooklog.txt Wed Aug 19 18:37:53 2009
@@ -20,12 +20,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_hooklog.py`_ plugin source code
2. put it somewhere as ``pytest_hooklog.py`` into your import path
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
Modified: py/dist/doc/test/plugin/hookspec.txt
==============================================================================
--- py/dist/doc/test/plugin/hookspec.txt (original)
+++ py/dist/doc/test/plugin/hookspec.txt Wed Aug 19 18:37:53 2009
@@ -97,7 +97,7 @@
""" called before test session finishes. """
pytest__teardown_final.firstresult = True
- def pytest__teardown_final_logerror(rep):
+ def pytest__teardown_final_logerror(report):
""" called if runtest_teardown_final failed. """
# -------------------------------------------------------------------------
@@ -114,8 +114,8 @@
# hooks for influencing reporting (invoked from pytest_terminal)
# -------------------------------------------------------------------------
- def pytest_report_teststatus(rep):
- """ return shortletter and verbose word. """
+ def pytest_report_teststatus(report):
+ """ return result-category, shortletter and verbose word for reporting."""
pytest_report_teststatus.firstresult = True
def pytest_terminal_summary(terminalreporter):
Modified: py/dist/doc/test/plugin/index.txt
==============================================================================
--- py/dist/doc/test/plugin/index.txt (original)
+++ py/dist/doc/test/plugin/index.txt Wed Aug 19 18:37:53 2009
@@ -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.
@@ -13,19 +13,21 @@
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.
-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.
-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.
@@ -35,8 +37,20 @@
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.
Modified: py/dist/doc/test/plugin/keyword.txt
==============================================================================
--- py/dist/doc/test/plugin/keyword.txt (original)
+++ py/dist/doc/test/plugin/keyword.txt Wed Aug 19 18:37:53 2009
@@ -35,12 +35,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_keyword.py`_ plugin source code
2. put it somewhere as ``pytest_keyword.py`` into your import path
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
Modified: py/dist/doc/test/plugin/links.txt
==============================================================================
--- py/dist/doc/test/plugin/links.txt (original)
+++ py/dist/doc/test/plugin/links.txt Wed Aug 19 18:37:53 2009
@@ -1,33 +1,37 @@
+.. _`helpconfig`: helpconfig.html
.. _`terminal`: terminal.html
-.. _`pytest_recwarn.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/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
-.. _`pytest_monkeypatch.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/py/test/plugin/pytest_monkeypatch.py
-.. _`pytest_keyword.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/py/test/plugin/pytest_keyword.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/1.0.1/py/test/plugin/pytest_keyword.py
.. _`pastebin`: pastebin.html
.. _`plugins`: index.html
-.. _`pytest_capture.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/py/test/plugin/pytest_capture.py
-.. _`pytest_doctest.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/py/test/plugin/pytest_doctest.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/1.0.1/py/test/plugin/pytest_doctest.py
.. _`capture`: capture.html
-.. _`hooklog`: hooklog.html
-.. _`pytest_restdoc.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/py/test/plugin/pytest_restdoc.py
-.. _`pytest_hooklog.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/py/test/plugin/pytest_hooklog.py
-.. _`pytest_pastebin.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/py/test/plugin/pytest_pastebin.py
-.. _`pytest_figleaf.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/py/test/plugin/pytest_figleaf.py
+.. _`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/1.0.1/py/test/plugin/pytest_restdoc.py
.. _`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
+.. _`pytest_helpconfig.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_helpconfig.py
.. _`oejskit`: oejskit.html
-.. _`pytest_xfail.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/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
-.. _`extend`: ../extend.html
-.. _`pytest_terminal.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/py/test/plugin/pytest_terminal.py
+.. _`customize`: ../customize.html
+.. _`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
-.. _`pytest_pdb.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/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
.. _`resultlog`: resultlog.html
.. _`keyword`: keyword.html
.. _`restdoc`: restdoc.html
-.. _`pytest_unittest.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/py/test/plugin/pytest_unittest.py
-.. _`doctest`: doctest.html
-.. _`pytest_resultlog.py`: http://bitbucket.org/hpk42/py-trunk/raw/3b3ea41060652c47739450a590c4d71625bc05bd/py/test/plugin/pytest_resultlog.py
+.. _`pytest_unittest.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_unittest.py
+.. _`nose`: nose.html
+.. _`pytest_resultlog.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_resultlog.py
.. _`pdb`: pdb.html
Modified: py/dist/doc/test/plugin/monkeypatch.txt
==============================================================================
--- py/dist/doc/test/plugin/monkeypatch.txt (original)
+++ py/dist/doc/test/plugin/monkeypatch.txt Wed Aug 19 18:37:53 2009
@@ -10,7 +10,7 @@
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
to set the environment variable ``ENV1`` and patch the
``os.path.abspath`` function to return a particular value during a test
@@ -26,7 +26,16 @@
The function argument will do the modifications and memorize the
old state. After the test function finished execution all
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/
@@ -50,12 +59,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_monkeypatch.py`_ plugin source code
2. put it somewhere as ``pytest_monkeypatch.py`` into your import path
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
Added: py/dist/doc/test/plugin/nose.txt
==============================================================================
--- (empty file)
+++ py/dist/doc/test/plugin/nose.txt Wed Aug 19 18:37:53 2009
@@ -0,0 +1,50 @@
+
+pytest_nose plugin
+==================
+
+nose-compatibility plugin: allow to run nose test suites natively.
+
+.. contents::
+ :local:
+
+This is an experimental plugin for allowing to run tests written
+in 'nosetests' style with py.test.
+
+Usage
+-------------
+
+type::
+
+ py.test # instead of 'nosetests'
+
+and you should be able to run nose style tests. You will of course
+get py.test style reporting and its feature set.
+
+Issues?
+----------------
+
+If you find issues or have suggestions please run::
+
+ py.test --pastebin=all
+
+and send the resulting URL to a some contact channel.
+
+Known issues
+------------------
+
+- nose-style doctests are not collected and executed correctly,
+ also fixtures don't work.
+
+- no nose-configuration is recognized
+
+Start improving this plugin in 30 seconds
+=========================================
+
+
+1. Download `pytest_nose.py`_ plugin source code
+2. put it somewhere as ``pytest_nose.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
Modified: py/dist/doc/test/plugin/pastebin.txt
==============================================================================
--- py/dist/doc/test/plugin/pastebin.txt (original)
+++ py/dist/doc/test/plugin/pastebin.txt Wed Aug 19 18:37:53 2009
@@ -14,7 +14,7 @@
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
for example ``-x`` if you only want to send one particular failure.
@@ -35,12 +35,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_pastebin.py`_ plugin source code
2. put it somewhere as ``pytest_pastebin.py`` into your import path
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
Modified: py/dist/doc/test/plugin/pdb.txt
==============================================================================
--- py/dist/doc/test/plugin/pdb.txt (original)
+++ py/dist/doc/test/plugin/pdb.txt Wed Aug 19 18:37:53 2009
@@ -20,12 +20,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_pdb.py`_ plugin source code
2. put it somewhere as ``pytest_pdb.py`` into your import path
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
Modified: py/dist/doc/test/plugin/recwarn.txt
==============================================================================
--- py/dist/doc/test/plugin/recwarn.txt (original)
+++ py/dist/doc/test/plugin/recwarn.txt Wed Aug 19 18:37:53 2009
@@ -50,12 +50,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_recwarn.py`_ plugin source code
2. put it somewhere as ``pytest_recwarn.py`` into your import path
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
Modified: py/dist/doc/test/plugin/restdoc.txt
==============================================================================
--- py/dist/doc/test/plugin/restdoc.txt (original)
+++ py/dist/doc/test/plugin/restdoc.txt Wed Aug 19 18:37:53 2009
@@ -24,12 +24,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_restdoc.py`_ plugin source code
2. put it somewhere as ``pytest_restdoc.py`` into your import path
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
Modified: py/dist/doc/test/plugin/resultlog.txt
==============================================================================
--- py/dist/doc/test/plugin/resultlog.txt (original)
+++ py/dist/doc/test/plugin/resultlog.txt Wed Aug 19 18:37:53 2009
@@ -20,12 +20,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_resultlog.py`_ plugin source code
2. put it somewhere as ``pytest_resultlog.py`` into your import path
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
Modified: py/dist/doc/test/plugin/terminal.txt
==============================================================================
--- py/dist/doc/test/plugin/terminal.txt (original)
+++ py/dist/doc/test/plugin/terminal.txt Wed Aug 19 18:37:53 2009
@@ -28,12 +28,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_terminal.py`_ plugin source code
2. put it somewhere as ``pytest_terminal.py`` into your import path
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
Modified: py/dist/doc/test/plugin/unittest.txt
==============================================================================
--- py/dist/doc/test/plugin/unittest.txt (original)
+++ py/dist/doc/test/plugin/unittest.txt Wed Aug 19 18:37:53 2009
@@ -23,12 +23,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_unittest.py`_ plugin source code
2. put it somewhere as ``pytest_unittest.py`` into your import path
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
Modified: py/dist/doc/test/plugin/xfail.txt
==============================================================================
--- py/dist/doc/test/plugin/xfail.txt (original)
+++ py/dist/doc/test/plugin/xfail.txt Wed Aug 19 18:37:53 2009
@@ -25,12 +25,10 @@
=========================================
-Do you find the above documentation or the plugin itself lacking?
-
1. Download `pytest_xfail.py`_ plugin source code
2. put it somewhere as ``pytest_xfail.py`` into your import path
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
Modified: py/dist/doc/test/quickstart.txt
==============================================================================
--- py/dist/doc/test/quickstart.txt (original)
+++ py/dist/doc/test/quickstart.txt Wed Aug 19 18:37:53 2009
@@ -7,27 +7,61 @@
.. _here: ../download.html#no-setuptools
-This document assumes basic python knowledge and a working `setuptools
-installation`_ (otherwise see here_). You can install
-the py lib and py.test by typing::
+
+With a `setuptools installation`_ (otherwise see here_) you can type::
easy_install -U py
-Now open a file ``test_sample.py`` file and put the following
-example content into it::
+On Linux systems you may need to execute this as the superuser and
+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
+ def func(x):
+ return x + 1
def test_answer():
- assert 42 == 43
+ assert f(3) == 5
You can now run the test file like this::
- py.test test_sample.py
+ py.test test_sample.py
+
+and will see output like this:
+
+.. 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
-and will see an error report on the failing assert statement.
-For further information please refer to `features`_
-or checkout the `tutorials`_ page for more introduction material.
+`contact`_: many ways for feedback and questions
+.. _`contact`: ../contact.html
.. _`automatically collected`: features.html#autocollect
.. _download: ../download.html
.. _features: features.html
Added: py/dist/doc/test/talks.txt
==============================================================================
--- (empty file)
+++ py/dist/doc/test/talks.txt Wed Aug 19 18:37:53 2009
@@ -0,0 +1,61 @@
+==========================
+Talks and Tutorials
+==========================
+
+.. _`funcargs`: funcargs.html
+
+tutorial examples and blog postings
+---------------------------------------------
+
+function arguments:
+
+- `application setup in test functions with funcargs`_
+- `making funcargs dependendent on command line options`_
+- `monkey patching done right`_ (blog post, consult `monkeypatch
+ plugin`_ for actual 1.0 API)
+
+test parametrization:
+
+- `generating parametrized tests with funcargs`_
+- `parametrizing tests, generalized`_ (blog post)
+- `putting test-hooks into local or global plugins`_ (blog post)
+
+distributed testing:
+
+- `simultanously test your code on all platforms`_ (blog entry)
+
+plugin specific examples:
+
+- `many examples in the docs for plugins`_
+
+.. _`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
+.. _`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/
+.. _`monkey patching done right`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/
+.. _`putting test-hooks into local or global plugins`: http://tetamap.wordpress.com/2009/05/14/putting-test-hooks-into-local-and-global-plugins/
+.. _`parametrizing tests, generalized`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/
+.. _`generating parametrized tests with funcargs`: funcargs.html#test-generators
+
+conference talks and tutorials
+----------------------------------------
+
+- `ep2009-rapidtesting.pdf`_ tutorial slides (July 2009):
+
+ - testing terminology
+ - basic py.test usage, file system layout
+ - test function arguments (funcargs_) and test fixtures
+ - existing plugins
+ - distributed testing
+
+- `ep2009-pytest.pdf`_ 60 minute py.test talk, highlighting unique features and a roadmap (July 2009)
+
+- `pycon2009-pytest-introduction.zip`_ slides and files, extended version of py.test basic introduction, discusses more options, also introduces old-style xUnit setup, looponfailing and other features.
+
+- `pycon2009-pytest-advanced.pdf`_ contain a slightly older version of funcargs and distributed testing, compared to the EuroPython 2009 slides.
+
+.. _`ep2009-rapidtesting.pdf`: http://codespeak.net/download/py/ep2009-rapidtesting.pdf
+.. _`ep2009-pytest.pdf`: http://codespeak.net/download/py/ep2009-pytest.pdf
+.. _`pycon2009-pytest-introduction.zip`: http://codespeak.net/download/py/pycon2009-pytest-introduction.zip
+.. _`pycon2009-pytest-advanced.pdf`: http://codespeak.net/download/py/pycon2009-pytest-advanced.pdf
Added: py/dist/doc/test/test.html
==============================================================================
--- (empty file)
+++ py/dist/doc/test/test.html Wed Aug 19 18:37:53 2009
@@ -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>
+
Deleted: /py/dist/doc/test/test.txt
==============================================================================
--- /py/dist/doc/test/test.txt Wed Aug 19 18:37:53 2009
+++ (empty file)
@@ -1,37 +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.
-
-`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
-
-talks_: talk and tutorial slides
-
-.. _`available plugins`: plugin/index.html
-.. _talks: talks.html
-.. _quickstart: quickstart.html
-.. _features: features.html
-.. _funcargs: funcargs.html
-.. _extend: extend.html
-.. _config: config.html
-.. _`distributed testing`: dist.html
-
-
Modified: py/dist/doc/test/xunit_setup.txt
==============================================================================
--- py/dist/doc/test/xunit_setup.txt (original)
+++ py/dist/doc/test/xunit_setup.txt Wed Aug 19 18:37:53 2009
@@ -7,12 +7,10 @@
Note:
- Since version 1.0 py.test offers funcargs_ for both
- simple and complex test setup needs. Especially
- for functional and integration, but also for unit testing, it is
- highly recommended that you use this new method.
+ Since version 1.0 funcargs_ present the recommended way
+ to manage flexible and scalable test setups.
-Python, Java and other languages have a tradition
+Python, Java and many other languages have a tradition
of using xUnit_ style testing. This typically
involves the call of a ``setup`` method before
a test function is run and ``teardown`` after
Modified: py/dist/doc/xml.txt
==============================================================================
--- py/dist/doc/xml.txt (original)
+++ py/dist/doc/xml.txt Wed Aug 19 18:37:53 2009
@@ -166,4 +166,4 @@
your Tags. Hum, it's probably harder to explain this than to
actually code it :-)
-.. _`py.test`: test/test.html
+.. _`py.test`: test/index.html
Modified: py/dist/example/assertion/failure_demo.py
==============================================================================
--- py/dist/example/assertion/failure_demo.py (original)
+++ py/dist/example/assertion/failure_demo.py Wed Aug 19 18:37:53 2009
@@ -11,6 +11,13 @@
assert (a ==
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):
def test_simple(self):
def f():
@@ -96,14 +103,9 @@
if namenotexi:
pass
- def test_generator(self):
- yield None
-
def func1(self):
assert 41 == 42
- def test_generator2(self):
- yield self.func1
# thanks to Matthew Scott for this test
def test_dynamic_compile_shows_nicely():
Modified: py/dist/example/assertion/test_failures.py
==============================================================================
--- py/dist/example/assertion/test_failures.py (original)
+++ py/dist/example/assertion/test_failures.py Wed Aug 19 18:37:53 2009
@@ -11,4 +11,4 @@
assert failed == 20, failed
colreports = reprec.getreports("pytest_collectreport")
failed = len([x.failed for x in colreports])
- assert failed == 5
+ assert failed == 4
Modified: py/dist/py/__init__.py
==============================================================================
--- py/dist/py/__init__.py (original)
+++ py/dist/py/__init__.py Wed Aug 19 18:37:53 2009
@@ -20,7 +20,7 @@
from initpkg import initpkg
trunk = None
-version = trunk or "1.0.0"
+version = trunk or "1.0.1"
initpkg(__name__,
description = "py.test and pylib: advanced testing tool and networking lib",
@@ -52,7 +52,7 @@
'_com.Registry' : ('./_com.py', 'Registry'),
'_com.MultiCall' : ('./_com.py', 'MultiCall'),
'_com.comregistry' : ('./_com.py', 'comregistry'),
- '_com.Hooks' : ('./_com.py', 'Hooks'),
+ '_com.HookRelay' : ('./_com.py', 'HookRelay'),
# py lib cmdline tools
'cmdline.pytest' : ('./cmdline/pytest.py', 'main',),
Modified: py/dist/py/_com.py
==============================================================================
--- py/dist/py/_com.py (original)
+++ py/dist/py/_com.py Wed Aug 19 18:37:53 2009
@@ -5,67 +5,53 @@
import py
class MultiCall:
- """ Manage a specific call into many python functions/methods.
+ """ execute a call into multiple python functions/methods. """
- Simple example:
- MultiCall([list1.append, list2.append], 42).execute()
- """
-
- def __init__(self, methods, *args, **kwargs):
+ def __init__(self, methods, kwargs, firstresult=False):
self.methods = methods[:]
- self.args = args
- self.kwargs = kwargs
+ self.kwargs = kwargs.copy()
+ self.kwargs['__multicall__'] = self
self.results = []
+ self.firstresult = firstresult
+
+ def __repr__(self):
+ status = "%d results, %d meths" % (len(self.results), len(self.methods))
+ return "<MultiCall %s, kwargs=%r>" %(status, self.kwargs)
- def execute(self, firstresult=False):
+ def execute(self):
while self.methods:
- currentmethod = self.methods.pop()
- res = self.execute_method(currentmethod)
- if hasattr(self, '_ex1'):
- self.results = [res]
- break
+ method = self.methods.pop()
+ kwargs = self.getkwargs(method)
+ res = method(**kwargs)
if res is not None:
self.results.append(res)
- if firstresult:
- break
- if not firstresult:
+ if self.firstresult:
+ return res
+ if not self.firstresult:
return self.results
- if self.results:
- return self.results[-1]
- def execute_method(self, currentmethod):
- self.currentmethod = currentmethod
- # provide call introspection if "__call__" is the first positional argument
- if hasattr(currentmethod, 'im_self'):
- varnames = currentmethod.im_func.func_code.co_varnames
- needscall = varnames[1:2] == ('__call__',)
- else:
+ def getkwargs(self, method):
+ kwargs = {}
+ for argname in varnames(method):
try:
- varnames = currentmethod.func_code.co_varnames
- except AttributeError:
- # builtin function
- varnames = ()
- needscall = varnames[:1] == ('__call__',)
- if needscall:
- return currentmethod(self, *self.args, **self.kwargs)
- else:
- #try:
- return currentmethod(*self.args, **self.kwargs)
- #except TypeError:
- # print currentmethod.__module__, currentmethod.__name__, self.args, self.kwargs
- # raise
-
- def exclude_other_results(self):
- self._ex1 = True
-
+ kwargs[argname] = self.kwargs[argname]
+ except KeyError:
+ pass # might be optional param
+ return kwargs
+
+def varnames(rawcode):
+ ismethod = hasattr(rawcode, 'im_self')
+ rawcode = getattr(rawcode, 'im_func', rawcode)
+ rawcode = getattr(rawcode, 'func_code', rawcode)
+ try:
+ return rawcode.co_varnames[ismethod:]
+ except AttributeError:
+ return ()
class Registry:
"""
- Manage Plugins: Load plugins and manage calls to plugins.
+ Manage Plugins: register/unregister call calls to plugins.
"""
- logfile = None
- MultiCall = MultiCall
-
def __init__(self, plugins=None):
if plugins is None:
plugins = []
@@ -73,6 +59,7 @@
def register(self, plugin):
assert not isinstance(plugin, str)
+ assert not plugin in self._plugins
self._plugins.append(plugin)
def unregister(self, plugin):
@@ -97,45 +84,39 @@
l.reverse()
return l
-class Hooks:
- def __init__(self, hookspecs, registry=None):
+class HookRelay:
+ def __init__(self, hookspecs, registry):
self._hookspecs = hookspecs
- if registry is None:
- registry = py._com.comregistry
- self.registry = registry
+ self._registry = registry
for name, method in vars(hookspecs).items():
if name[:1] != "_":
- firstresult = getattr(method, 'firstresult', False)
- mm = HookCall(registry, name, firstresult=firstresult)
- setattr(self, name, mm)
- def __repr__(self):
- return "<Hooks %r %r>" %(self._hookspecs, self.registry)
+ setattr(self, name, self._makecall(name))
-class HookCall:
- def __init__(self, registry, name, firstresult, extralookup=None):
- self.registry = registry
+ def _makecall(self, name, extralookup=None):
+ hookspecmethod = getattr(self._hookspecs, name)
+ firstresult = getattr(hookspecmethod, 'firstresult', False)
+ return HookCaller(self, name, firstresult=firstresult,
+ extralookup=extralookup)
+
+ def _getmethods(self, name, extralookup=()):
+ return self._registry.listattr(name, extra=extralookup)
+
+ def _performcall(self, name, multicall):
+ return multicall.execute()
+
+class HookCaller:
+ def __init__(self, hookrelay, name, firstresult, extralookup=()):
+ self.hookrelay = hookrelay
self.name = name
self.firstresult = firstresult
self.extralookup = extralookup and [extralookup] or ()
- def clone(self, extralookup):
- return HookCall(self.registry, self.name, self.firstresult, extralookup)
-
def __repr__(self):
- mode = self.firstresult and "firstresult" or "each"
- return "<HookCall %r mode=%s %s>" %(self.name, mode, self.registry)
-
- def __call__(self, *args, **kwargs):
- if args:
- raise TypeError("only keyword arguments allowed "
- "for api call to %r" % self.name)
- attr = self.registry.listattr(self.name, extra=self.extralookup)
- mc = MultiCall(attr, **kwargs)
- # XXX this should be doable from a hook impl:
- if self.registry.logfile:
- self.registry.logfile.write("%s(**%s) # firstresult=%s\n" %
- (self.name, kwargs, self.firstresult))
- self.registry.logfile.flush()
- return mc.execute(firstresult=self.firstresult)
+ return "<HookCaller %r>" %(self.name,)
-comregistry = Registry()
+ def __call__(self, **kwargs):
+ methods = self.hookrelay._getmethods(self.name, self.extralookup)
+ mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
+ return self.hookrelay._performcall(self.name, mc)
+
+comregistry = Registry([])
Deleted: /py/dist/py/bin/_genscripts.py
==============================================================================
--- /py/dist/py/bin/_genscripts.py Wed Aug 19 18:37:53 2009
+++ (empty file)
@@ -1,34 +0,0 @@
-from _findpy import py
-
-mydir = py.magic.autopath().dirpath()
-
-def getbasename(name):
- assert name[:2] == "py"
- return "py." + name[2:]
-
-def genscript_unix(name):
- basename = getbasename(name)
- path = mydir.join(basename)
- path.write(py.code.Source("""
- #!/usr/bin/env python
- from _findpy import py
- py.cmdline.%s()
- """ % name).strip())
- path.chmod(0755)
-
-def genscript_windows(name):
- basename = getbasename(name)
- winbasename = basename + ".cmd"
- path = mydir.join("win32").join(winbasename)
- path.write(py.code.Source("""
- @echo off
- python "%%~dp0\..\%s" %%*
- """ % (basename)).strip())
-
-if __name__ == "__main__":
- for name in dir(py.cmdline):
- if name[0] != "_":
- genscript_unix(name)
- genscript_windows(name)
-
-
Deleted: /py/dist/py/bin/gendoc.py
==============================================================================
--- /py/dist/py/bin/gendoc.py Wed Aug 19 18:37:53 2009
+++ (empty file)
@@ -1,23 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import os
-from _findpy import py
-try:
- import apigen
-except ImportError:
- print 'Can not find apigen - make sure PYTHONPATH is set correctly!'
- py.std.sys.exit()
-else:
- args = list(sys.argv[1:])
- args.extend(['-p', 'apigen'])
- argkeys = [a.split('=')[0] for a in args]
- if '--apigen' not in argkeys:
- args.append('--apigen')
- if '--apigenscript' not in argkeys:
- fpath = os.path.join(
- os.path.dirname(apigen.__file__), 'tool', 'py_build', 'build.py')
- args.append('--apigenscript=%s' % (fpath,))
- if '--apigenpath' not in argkeys:
- args.append('--apigenpath=api')
- py.test.cmdline.main(args)
Modified: py/dist/py/code/excinfo.py
==============================================================================
--- py/dist/py/code/excinfo.py (original)
+++ py/dist/py/code/excinfo.py Wed Aug 19 18:37:53 2009
@@ -39,8 +39,7 @@
"""
lines = py.std.traceback.format_exception_only(self.type, self.value)
text = ''.join(lines)
- if text.endswith('\n'):
- text = text[:-1]
+ text = text.rstrip()
if tryshort:
if text.startswith(self._striptext):
text = text[len(self._striptext):]
Modified: py/dist/py/code/testing/test_excinfo.py
==============================================================================
--- py/dist/py/code/testing/test_excinfo.py (original)
+++ py/dist/py/code/testing/test_excinfo.py Wed Aug 19 18:37:53 2009
@@ -200,6 +200,11 @@
def test_excinfo_exconly():
excinfo = py.test.raises(ValueError, h)
assert excinfo.exconly().startswith('ValueError')
+ excinfo = py.test.raises(ValueError,
+ "raise ValueError('hello\\nworld')")
+ msg = excinfo.exconly(tryshort=True)
+ assert msg.startswith('ValueError')
+ assert msg.endswith("world")
def test_excinfo_repr():
excinfo = py.test.raises(ValueError, h)
@@ -242,7 +247,6 @@
assert s.startswith("def get")
def test_codepath_Queue_example():
- py.test.skip("try harder to get at the paths of code objects.")
import Queue
try:
Queue.Queue().get(timeout=0.001)
Modified: py/dist/py/code/testing/test_source.py
==============================================================================
--- py/dist/py/code/testing/test_source.py (original)
+++ py/dist/py/code/testing/test_source.py Wed Aug 19 18:37:53 2009
@@ -173,8 +173,8 @@
assert len(source) == 6
assert source.getstatementrange(2) == (1, 4)
+ @py.test.mark.xfail
def test_getstatementrange_bug2(self):
- py.test.skip("fix me (issue19)")
source = Source("""\
assert (
33
@@ -300,8 +300,8 @@
lines = deindent(source.splitlines())
assert lines == ['', 'def f():', ' def g():', ' pass', ' ']
+ at py.test.mark.xfail
def test_source_of_class_at_eof_without_newline():
- py.test.skip("CPython's inspect.getsource is buggy")
# this test fails because the implicit inspect.getsource(A) below
# does not return the "x = 1" last line.
tmpdir = py.test.ensuretemp("source_write_read")
Modified: py/dist/py/execnet/gateway.py
==============================================================================
--- py/dist/py/execnet/gateway.py (original)
+++ py/dist/py/execnet/gateway.py Wed Aug 19 18:37:53 2009
@@ -88,8 +88,8 @@
self._channelfactory = ChannelFactory(self, _startcount)
self._cleanup.register(self)
if _startcount == 1: # only import 'py' on the "client" side
- from py._com import Hooks
- self.hook = Hooks(ExecnetAPI)
+ import py
+ self.hook = py._com.HookRelay(ExecnetAPI, py._com.comregistry)
else:
self.hook = ExecnetAPI()
Modified: py/dist/py/execnet/gwmanage.py
==============================================================================
--- py/dist/py/execnet/gwmanage.py (original)
+++ py/dist/py/execnet/gwmanage.py Wed Aug 19 18:37:53 2009
@@ -21,7 +21,8 @@
if not spec.chdir and not spec.popen:
spec.chdir = defaultchdir
self.specs.append(spec)
- self.hook = py._com.Hooks(py.execnet._HookSpecs)
+ self.hook = py._com.HookRelay(
+ py.execnet._HookSpecs, py._com.comregistry)
def makegateways(self):
assert not self.gateways
Modified: py/dist/py/io/stdcapture.py
==============================================================================
--- py/dist/py/io/stdcapture.py (original)
+++ py/dist/py/io/stdcapture.py Wed Aug 19 18:37:53 2009
@@ -76,7 +76,7 @@
os.close(fd)
if out:
tmpfile = None
- if isinstance(out, file):
+ if hasattr(out, 'write'):
tmpfile = out
self.out = py.io.FDCapture(1, tmpfile=tmpfile)
if patchsys:
@@ -84,7 +84,7 @@
if err:
if mixed and out:
tmpfile = self.out.tmpfile
- elif isinstance(err, file):
+ elif hasattr(err, 'write'):
tmpfile = err
else:
tmpfile = None
Modified: py/dist/py/io/terminalwriter.py
==============================================================================
--- py/dist/py/io/terminalwriter.py (original)
+++ py/dist/py/io/terminalwriter.py Wed Aug 19 18:37:53 2009
@@ -139,6 +139,7 @@
Black=40, Red=41, Green=42, Yellow=43,
Blue=44, Purple=45, Cyan=46, White=47,
bold=1, light=2, blink=5, invert=7)
+ _encoding = "utf-8"
def __init__(self, file=None, stringio=False):
if file is None:
@@ -194,58 +195,27 @@
def write(self, s, **kw):
if s:
- s = str(s)
+ s = self._getbytestring(s)
if self.hasmarkup and kw:
s = self.markup(s, **kw)
self._file.write(s)
- self._file.flush()
+ self._file.flush()
+
+ def _getbytestring(self, s):
+ if isinstance(s, unicode):
+ return s.encode(self._encoding)
+ elif not isinstance(s, str):
+ return str(s)
+ return s
def line(self, s='', **kw):
self.write(s, **kw)
self.write('\n')
-class Win32ConsoleWriter(object):
-
- def __init__(self, file=None, stringio=False):
- if file is None:
- if stringio:
- self.stringio = file = py.std.cStringIO.StringIO()
- else:
- file = py.std.sys.stdout
- elif callable(file):
- file = WriteFile(file)
- self._file = file
- self.fullwidth = get_terminal_width()
- self.hasmarkup = should_do_markup(file)
-
- def sep(self, sepchar, title=None, fullwidth=None, **kw):
- if fullwidth is None:
- fullwidth = self.fullwidth
- # the goal is to have the line be as long as possible
- # under the condition that len(line) <= fullwidth
- if title is not None:
- # we want 2 + 2*len(fill) + len(title) <= fullwidth
- # i.e. 2 + 2*len(sepchar)*N + len(title) <= fullwidth
- # 2*len(sepchar)*N <= fullwidth - len(title) - 2
- # N <= (fullwidth - len(title) - 2) // (2*len(sepchar))
- N = (fullwidth - len(title) - 2) // (2*len(sepchar))
- fill = sepchar * N
- line = "%s %s %s" % (fill, title, fill)
- else:
- # we want len(sepchar)*N <= fullwidth
- # i.e. N <= fullwidth // len(sepchar)
- line = sepchar * (fullwidth // len(sepchar))
- # in some situations there is room for an extra sepchar at the right,
- # in particular if we consider that with a sepchar like "_ " the
- # trailing space is not important at the end of the line
- if len(line) + len(sepchar.rstrip()) <= fullwidth:
- line += sepchar.rstrip()
-
- self.line(line, **kw)
-
+class Win32ConsoleWriter(TerminalWriter):
def write(self, s, **kw):
if s:
- s = str(s)
+ s = self._getbytestring(s)
if self.hasmarkup:
handle = GetStdHandle(STD_OUTPUT_HANDLE)
@@ -269,8 +239,8 @@
if self.hasmarkup:
SetConsoleTextAttribute(handle, FOREGROUND_WHITE)
- def line(self, s='', **kw):
- self.write(s + '\n', **kw)
+ def line(self, s="", **kw):
+ self.write(s+"\n", **kw)
if sys.platform == 'win32':
TerminalWriter = Win32ConsoleWriter
Modified: py/dist/py/io/testing/test_terminalwriter.py
==============================================================================
--- py/dist/py/io/testing/test_terminalwriter.py (original)
+++ py/dist/py/io/testing/test_terminalwriter.py Wed Aug 19 18:37:53 2009
@@ -37,6 +37,16 @@
assert len(l) == 1
assert l[0] == "hello\n"
+ def test_line_unicode(self):
+ tw = self.getwriter()
+ for encoding in 'utf8', 'latin1':
+ tw._encoding = encoding
+ msg = unicode('b\u00f6y', 'utf8')
+ tw.line(msg)
+ l = self.getlines()
+ assert not isinstance(l[0], unicode)
+ assert unicode(l[0], encoding) == msg + "\n"
+
def test_sep_no_title(self):
tw = self.getwriter()
tw.sep("-", fullwidth=60)
@@ -85,6 +95,16 @@
l = self.getlines()
assert len(l[0]) == len(l[1])
+class TestTmpfile(BaseTests):
+ def getwriter(self):
+ self.path = py.test.config.ensuretemp("terminalwriter").ensure("tmpfile")
+ self.tw = py.io.TerminalWriter(self.path.open('w+'))
+ return self.tw
+ def getlines(self):
+ io = self.tw._file
+ io.flush()
+ return self.path.open('r').readlines()
+
class TestStringIO(BaseTests):
def getwriter(self):
self.tw = py.io.TerminalWriter(stringio=True)
Modified: py/dist/py/misc/testing/test_com.py
==============================================================================
--- py/dist/py/misc/testing/test_com.py (original)
+++ py/dist/py/misc/testing/test_com.py Wed Aug 19 18:37:53 2009
@@ -1,92 +1,89 @@
import py
import os
-from py._com import Registry, MultiCall
-from py._com import Hooks
-
-pytest_plugins = "xfail"
+from py.__._com import Registry, MultiCall, HookRelay, varnames
+def test_varnames():
+ def f(x):
+ pass
+ class A:
+ def f(self, y):
+ pass
+ assert varnames(f) == ("x",)
+ assert varnames(A.f) == ('y',)
+ assert varnames(A().f) == ('y',)
+
class TestMultiCall:
def test_uses_copy_of_methods(self):
l = [lambda: 42]
- mc = MultiCall(l)
+ mc = MultiCall(l, {})
+ repr(mc)
l[:] = []
res = mc.execute()
return res == 42
def test_call_passing(self):
class P1:
- def m(self, __call__, x):
- assert __call__.currentmethod == self.m
- assert len(__call__.results) == 1
- assert not __call__.methods
+ def m(self, __multicall__, x):
+ assert len(__multicall__.results) == 1
+ assert not __multicall__.methods
return 17
class P2:
- def m(self, __call__, x):
- assert __call__.currentmethod == self.m
- assert __call__.args
- assert __call__.results == []
- assert __call__.methods
+ def m(self, __multicall__, x):
+ assert __multicall__.results == []
+ assert __multicall__.methods
return 23
p1 = P1()
p2 = P2()
- multicall = MultiCall([p1.m, p2.m], 23)
+ multicall = MultiCall([p1.m, p2.m], {'x': 23})
+ assert "23" in repr(multicall)
reslist = multicall.execute()
assert len(reslist) == 2
# ensure reversed order
assert reslist == [23, 17]
- def test_optionalcallarg(self):
- class P1:
- def m(self, x):
- return x
- call = MultiCall([P1().m], 23)
- assert call.execute() == [23]
- assert call.execute(firstresult=True) == 23
-
- def test_call_subexecute(self):
- def m(__call__):
- subresult = __call__.execute(firstresult=True)
- return subresult + 1
-
- def n():
- return 1
+ def test_keyword_args(self):
+ def f(x):
+ return x + 1
+ class A:
+ def f(self, x, y):
+ return x + y
+ multicall = MultiCall([f, A().f], dict(x=23, y=24))
+ assert "'x': 23" in repr(multicall)
+ assert "'y': 24" in repr(multicall)
+ reslist = multicall.execute()
+ assert reslist == [24+23, 24]
+ assert "2 results" in repr(multicall)
- call = MultiCall([n, m])
- res = call.execute(firstresult=True)
- assert res == 2
+ def test_keywords_call_error(self):
+ multicall = MultiCall([lambda x: x], {})
+ py.test.raises(TypeError, "multicall.execute()")
- def test_call_exclude_other_results(self):
- def m(__call__):
- __call__.exclude_other_results()
- return 10
+ def test_call_subexecute(self):
+ def m(__multicall__):
+ subresult = __multicall__.execute()
+ return subresult + 1
def n():
return 1
- call = MultiCall([n, n, m, n])
+ call = MultiCall([n, m], {}, firstresult=True)
res = call.execute()
- assert res == [10]
- # doesn't really make sense for firstresult-mode - because
- # we might not have had a chance to run at all.
- #res = call.execute(firstresult=True)
- #assert res == 10
+ assert res == 2
def test_call_none_is_no_result(self):
def m1():
return 1
def m2():
return None
- mc = MultiCall([m1, m2])
- res = mc.execute(firstresult=True)
+ res = MultiCall([m1, m2], {}, firstresult=True).execute()
assert res == 1
+ res = MultiCall([m1, m2], {}).execute()
+ assert res == [1]
class TestRegistry:
- def test_MultiCall(self):
- plugins = Registry()
- assert hasattr(plugins, "MultiCall")
def test_register(self):
registry = Registry()
@@ -130,14 +127,14 @@
def test_api_and_defaults():
assert isinstance(py._com.comregistry, Registry)
-class TestHooks:
+class TestHookRelay:
def test_happypath(self):
registry = Registry()
class Api:
def hello(self, arg):
pass
- mcm = Hooks(hookspecs=Api, registry=registry)
+ mcm = HookRelay(hookspecs=Api, registry=registry)
assert hasattr(mcm, 'hello')
assert repr(mcm.hello).find("hello") != -1
class Plugin:
@@ -148,23 +145,21 @@
assert l == [4]
assert not hasattr(mcm, 'world')
- def test_needskeywordargs(self):
+ def test_only_kwargs(self):
registry = Registry()
class Api:
def hello(self, arg):
pass
- mcm = Hooks(hookspecs=Api, registry=registry)
- excinfo = py.test.raises(TypeError, "mcm.hello(3)")
- assert str(excinfo.value).find("only keyword arguments") != -1
- assert str(excinfo.value).find("hello(self, arg)")
+ mcm = HookRelay(hookspecs=Api, registry=registry)
+ py.test.raises(TypeError, "mcm.hello(3)")
- def test_firstresult(self):
+ def test_firstresult_definition(self):
registry = Registry()
class Api:
def hello(self, arg): pass
hello.firstresult = True
- mcm = Hooks(hookspecs=Api, registry=registry)
+ mcm = HookRelay(hookspecs=Api, registry=registry)
class Plugin:
def hello(self, arg):
return arg + 1
@@ -174,15 +169,16 @@
def test_default_plugins(self):
class Api: pass
- mcm = Hooks(hookspecs=Api)
- assert mcm.registry == py._com.comregistry
+ mcm = HookRelay(hookspecs=Api, registry=py._com.comregistry)
+ assert mcm._registry == py._com.comregistry
def test_hooks_extra_plugins(self):
registry = Registry()
class Api:
def hello(self, arg):
pass
- hook_hello = Hooks(hookspecs=Api, registry=registry).hello
+ hookrelay = HookRelay(hookspecs=Api, registry=registry)
+ hook_hello = hookrelay.hello
class Plugin:
def hello(self, arg):
return arg + 1
@@ -190,7 +186,7 @@
class Plugin2:
def hello(self, arg):
return arg + 2
- newhook = hook_hello.clone(extralookup=Plugin2())
+ newhook = hookrelay._makecall("hello", extralookup=Plugin2())
l = newhook(arg=3)
assert l == [5, 4]
l2 = hook_hello(arg=3)
Added: py/dist/py/misc/testing/test_install.py
==============================================================================
--- (empty file)
+++ py/dist/py/misc/testing/test_install.py Wed Aug 19 18:37:53 2009
@@ -0,0 +1,16 @@
+import py
+
+def test_make_sdist_and_run_it(capfd, py_setup, venv):
+ try:
+ sdist = py_setup.make_sdist(venv.path)
+ venv.easy_install(str(sdist))
+ gw = venv.makegateway()
+ ch = gw.remote_exec("import py ; channel.send(py.__version__)")
+ version = ch.receive()
+ assert version == py.__version__
+ except KeyboardInterrupt:
+ raise
+ except:
+ print capfd.readouterr()
+ raise
+ capfd.close()
Modified: py/dist/py/path/svn/testing/test_wccommand.py
==============================================================================
--- py/dist/py/path/svn/testing/test_wccommand.py (original)
+++ py/dist/py/path/svn/testing/test_wccommand.py Wed Aug 19 18:37:53 2009
@@ -225,6 +225,12 @@
'''
XMLWCStatus.fromstring(xml, self.root)
+ def test_status_wrong_xml(self):
+ # testing for XML without author - this used to raise an exception
+ xml = u'<entry path="/home/jean/zope/venv/projectdb/parts/development-products/DataGridField">\n<wc-status item="incomplete" props="none" revision="784">\n</wc-status>\n</entry>'
+ st = XMLWCStatus.fromstring(xml, self.root)
+ assert len(st.incomplete) == 1
+
def test_diff(self):
p = self.root / 'anotherfile'
out = p.diff(rev=2)
Modified: py/dist/py/path/svn/wccommand.py
==============================================================================
--- py/dist/py/path/svn/wccommand.py (original)
+++ py/dist/py/path/svn/wccommand.py Wed Aug 19 18:37:53 2009
@@ -671,6 +671,10 @@
wcpath = rootwcpath.join(path, abs=1)
rootstatus.ignored.append(wcpath)
continue
+ elif itemstatus == 'incomplete':
+ wcpath = rootwcpath.join(path, abs=1)
+ rootstatus.incomplete.append(wcpath)
+ continue
rev = statusel.getAttribute('revision')
if itemstatus == 'added' or itemstatus == 'none':
Modified: py/dist/py/test/collect.py
==============================================================================
--- py/dist/py/test/collect.py (original)
+++ py/dist/py/test/collect.py Wed Aug 19 18:37:53 2009
@@ -4,6 +4,7 @@
that is usually built iteratively.
"""
import py
+pydir = py.path.local(py.__file__).dirpath()
def configproperty(name):
def fget(self):
@@ -166,16 +167,13 @@
if colitem.fspath == fspath or colitem.name == basename:
l.append(colitem)
if not l:
- msg = ("Collector %r does not provide %r colitem "
- "existing colitems are: %s" %
- (cur, fspath, colitems))
- raise AssertionError(msg)
+ raise self.config.Error("can't collect: %s" %(fspath,))
if basenames:
if len(l) > 1:
msg = ("Collector %r has more than one %r colitem "
"existing colitems are: %s" %
(cur, fspath, colitems))
- raise AssertionError(msg)
+ raise self.config.Error("xxx-too many test types for: %s" % (fspath, ))
cur = l[0]
else:
if len(l) > 1:
@@ -332,6 +330,15 @@
"""
return self.collect_by_name(name)
+ def _prunetraceback(self, traceback):
+ if hasattr(self, 'fspath'):
+ path = self.fspath
+ ntraceback = traceback.cut(path=self.fspath)
+ if ntraceback == traceback:
+ ntraceback = ntraceback.cut(excludepath=pydir)
+ traceback = ntraceback.filter()
+ return traceback
+
class FSCollector(Collector):
def __init__(self, fspath, parent=None):
fspath = py.path.local(fspath)
@@ -388,7 +395,12 @@
def _ignore(self, path):
ignore_paths = self.config.getconftest_pathlist("collect_ignore", path=path)
- return ignore_paths and path in ignore_paths
+ return ignore_paths and path in ignore_paths
+ # XXX more refined would be:
+ if ignore_paths:
+ for p in ignore_paths:
+ if path == p or path.relto(p):
+ return True
def consider(self, path):
if self._ignore(path):
Modified: py/dist/py/test/config.py
==============================================================================
--- py/dist/py/test/config.py (original)
+++ py/dist/py/test/config.py Wed Aug 19 18:37:53 2009
@@ -64,7 +64,7 @@
val = eval(val)
opt.default = val
else:
- name = "pytest_option_" + opt.dest
+ name = "option_" + opt.dest
try:
opt.default = self._conftest.rget(name)
except (ValueError, KeyError):
Modified: py/dist/py/test/defaultconftest.py
==============================================================================
--- py/dist/py/test/defaultconftest.py (original)
+++ py/dist/py/test/defaultconftest.py Wed Aug 19 18:37:53 2009
@@ -10,6 +10,5 @@
Function = py.test.collect.Function
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"
Modified: py/dist/py/test/dist/dsession.py
==============================================================================
--- py/dist/py/test/dist/dsession.py (original)
+++ py/dist/py/test/dist/dsession.py Wed Aug 19 18:37:53 2009
@@ -77,8 +77,8 @@
self.item2nodes = {}
super(DSession, self).__init__(config=config)
- #def pytest_configure(self, __call__, config):
- # __call__.execute()
+ #def pytest_configure(self, __multicall__, config):
+ # __multicall__.execute()
# try:
# config.getxspecs()
# except config.Error:
Modified: py/dist/py/test/dist/testing/acceptance_test.py
==============================================================================
--- py/dist/py/test/dist/testing/acceptance_test.py (original)
+++ py/dist/py/test/dist/testing/acceptance_test.py Wed Aug 19 18:37:53 2009
@@ -65,7 +65,7 @@
""",
)
testdir.makeconftest("""
- pytest_option_tx = 'popen popen popen'.split()
+ option_tx = 'popen popen popen'.split()
""")
result = testdir.runpytest(p1, '-d')
result.stdout.fnmatch_lines([
Modified: py/dist/py/test/dist/txnode.py
==============================================================================
--- py/dist/py/test/dist/txnode.py (original)
+++ py/dist/py/test/dist/txnode.py Wed Aug 19 18:37:53 2009
@@ -145,11 +145,9 @@
if call.excinfo:
# likely it is not collectable here because of
# platform/import-dependency induced skips
- # XXX somewhat ugly shortcuts - also makes a collection
- # failure into an ItemTestReport - this might confuse
- # pytest_runtest_logreport hooks
+ # we fake a setup-error report with the obtained exception
+ # and do not care about capturing or non-runner hooks
rep = self.runner.pytest_runtest_makereport(item=item, call=call)
self.pytest_runtest_logreport(rep)
return
item.config.hook.pytest_runtest_protocol(item=item)
-
Modified: py/dist/py/test/plugin/conftest.py
==============================================================================
--- py/dist/py/test/plugin/conftest.py (original)
+++ py/dist/py/test/plugin/conftest.py Wed Aug 19 18:37:53 2009
@@ -15,10 +15,15 @@
# testdir.plugins.append(obj.testplugin)
# break
#else:
- basename = request.module.__name__.split(".")[-1]
- if basename.startswith("pytest_"):
+ modname = request.module.__name__.split(".")[-1]
+ if modname.startswith("pytest_"):
testdir.plugins.append(vars(request.module))
- testdir.plugins.append(basename)
+ testdir.plugins.append(modname)
+ #elif modname.startswith("test_pytest"):
+ # pname = modname[5:]
+ # assert pname not in testdir.plugins
+ # testdir.plugins.append(pname)
+ # #testdir.plugins.append(vars(request.module))
else:
pass # raise ValueError("need better support code")
return testdir
Modified: py/dist/py/test/plugin/hookspec.py
==============================================================================
--- py/dist/py/test/plugin/hookspec.py (original)
+++ py/dist/py/test/plugin/hookspec.py Wed Aug 19 18:37:53 2009
@@ -91,7 +91,7 @@
""" called before test session finishes. """
pytest__teardown_final.firstresult = True
-def pytest__teardown_final_logerror(rep):
+def pytest__teardown_final_logerror(report):
""" called if runtest_teardown_final failed. """
# -------------------------------------------------------------------------
@@ -108,8 +108,8 @@
# hooks for influencing reporting (invoked from pytest_terminal)
# -------------------------------------------------------------------------
-def pytest_report_teststatus(rep):
- """ return shortletter and verbose word. """
+def pytest_report_teststatus(report):
+ """ return result-category, shortletter and verbose word for reporting."""
pytest_report_teststatus.firstresult = True
def pytest_terminal_summary(terminalreporter):
Modified: py/dist/py/test/plugin/pytest__pytest.py
==============================================================================
--- py/dist/py/test/plugin/pytest__pytest.py (original)
+++ py/dist/py/test/plugin/pytest__pytest.py Wed Aug 19 18:37:53 2009
@@ -47,7 +47,7 @@
recorder = RecordCalls()
self._recorders[hookspecs] = recorder
self._comregistry.register(recorder)
- self.hook = py._com.Hooks(hookspecs, registry=self._comregistry)
+ self.hook = py._com.HookRelay(hookspecs, registry=self._comregistry)
def finish_recording(self):
for recorder in self._recorders.values():
Modified: py/dist/py/test/plugin/pytest_capture.py
==============================================================================
--- py/dist/py/test/plugin/pytest_capture.py (original)
+++ py/dist/py/test/plugin/pytest_capture.py Wed Aug 19 18:37:53 2009
@@ -32,7 +32,7 @@
If you set capturing values in a conftest file like this::
# conftest.py
- conf_capture = 'fd'
+ option_capture = 'fd'
then all tests in that directory will execute with "fd" style capturing.
@@ -107,18 +107,34 @@
def __init__(self):
self._method2capture = {}
+ def _maketempfile(self):
+ f = py.std.tempfile.TemporaryFile()
+ newf = py.io.dupfile(f)
+ encoding = getattr(newf, 'encoding', None) or "UTF-8"
+ return EncodedFile(newf, encoding)
+
+ def _makestringio(self):
+ return py.std.StringIO.StringIO()
+
def _startcapture(self, method):
if method == "fd":
- return py.io.StdCaptureFD()
+ return py.io.StdCaptureFD(
+ out=self._maketempfile(), err=self._maketempfile()
+ )
elif method == "sys":
- return py.io.StdCapture()
+ return py.io.StdCapture(
+ out=self._makestringio(), err=self._makestringio()
+ )
else:
raise ValueError("unknown capturing method: %r" % method)
def _getmethod(self, config, fspath):
if 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):
method = self._getmethod(item.config, item.fspath)
@@ -168,11 +184,11 @@
capfuncarg._finalize()
del self._capturing_funcargs
- def pytest_make_collect_report(self, __call__, collector):
+ def pytest_make_collect_report(self, __multicall__, collector):
method = self._getmethod(collector.config, collector.fspath)
self.resumecapture(method)
try:
- rep = __call__.execute(firstresult=True)
+ rep = __multicall__.execute()
finally:
outerr = self.suspendcapture()
addouterr(rep, outerr)
@@ -191,11 +207,11 @@
def pytest_runtest_teardown(self, item):
self.resumecapture_item(item)
- def pytest__teardown_final(self, __call__, session):
+ def pytest__teardown_final(self, __multicall__, session):
method = self._getmethod(session.config, None)
self.resumecapture(method)
try:
- rep = __call__.execute(firstresult=True)
+ rep = __multicall__.execute()
finally:
outerr = self.suspendcapture()
if rep:
@@ -206,9 +222,9 @@
if hasattr(self, '_capturing'):
self.suspendcapture()
- def pytest_runtest_makereport(self, __call__, item, call):
+ def pytest_runtest_makereport(self, __multicall__, item, call):
self.deactivate_funcargs()
- rep = __call__.execute(firstresult=True)
+ rep = __multicall__.execute()
outerr = self.suspendcapture()
outerr = (item.outerr[0] + outerr[0], item.outerr[1] + outerr[1])
if not rep.passed:
@@ -252,3 +268,22 @@
def close(self):
self.capture.reset()
del self.capture
+
+class EncodedFile(object):
+ def __init__(self, _stream, encoding):
+ self._stream = _stream
+ self.encoding = encoding
+
+ def write(self, obj):
+ if isinstance(obj, unicode):
+ 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)
+
Modified: py/dist/py/test/plugin/pytest_default.py
==============================================================================
--- py/dist/py/test/plugin/pytest_default.py (original)
+++ py/dist/py/test/plugin/pytest_default.py Wed Aug 19 18:37:53 2009
@@ -1,9 +1,10 @@
""" default hooks and general py.test options. """
+import sys
import py
-def pytest_pyfunc_call(__call__, pyfuncitem):
- if not __call__.execute(firstresult=True):
+def pytest_pyfunc_call(__multicall__, pyfuncitem):
+ if not __multicall__.execute():
testfunction = pyfuncitem.obj
if pyfuncitem._isyieldedfunction():
testfunction(*pyfuncitem._args)
@@ -60,13 +61,13 @@
action="store", dest="tbstyle", default='long',
type="choice", choices=['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. "))
group._addoption('-f', '--looponfail',
action="store_true", dest="looponfail", default=False,
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",
help="base temporary directory for this test run.")
@@ -146,7 +147,7 @@
def test_plugin_already_exists(testdir):
config = testdir.parseconfig("-p", "default")
- assert config.option.plugin == ['default']
+ assert config.option.plugins == ['default']
config.pluginmanager.do_configure(config)
Modified: py/dist/py/test/plugin/pytest_execnetcleanup.py
==============================================================================
--- py/dist/py/test/plugin/pytest_execnetcleanup.py (original)
+++ py/dist/py/test/plugin/pytest_execnetcleanup.py Wed Aug 19 18:37:53 2009
@@ -32,10 +32,10 @@
#for gw in l:
# gw.join()
- def pytest_pyfunc_call(self, __call__, pyfuncitem):
+ def pytest_pyfunc_call(self, __multicall__, pyfuncitem):
if self._gateways is not None:
gateways = self._gateways[:]
- res = __call__.execute(firstresult=True)
+ res = __multicall__.execute()
while len(self._gateways) > len(gateways):
self._gateways[-1].exit()
return res
Added: py/dist/py/test/plugin/pytest_helpconfig.py
==============================================================================
--- (empty file)
+++ py/dist/py/test/plugin/pytest_helpconfig.py Wed Aug 19 18:37:53 2009
@@ -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'),
+)
Modified: py/dist/py/test/plugin/pytest_hooklog.py
==============================================================================
--- py/dist/py/test/plugin/pytest_hooklog.py (original)
+++ py/dist/py/test/plugin/pytest_hooklog.py Wed Aug 19 18:37:53 2009
@@ -8,14 +8,27 @@
def pytest_configure(config):
hooklog = config.getvalue("hooklog")
if hooklog:
- assert not config.pluginmanager.comregistry.logfile
- config.pluginmanager.comregistry.logfile = open(hooklog, 'w')
+ config._hooklogfile = open(hooklog, 'w', 0)
+ config._hooklog_oldperformcall = config.hook._performcall
+ config.hook._performcall = (lambda name, multicall:
+ logged_call(name=name, multicall=multicall, config=config))
+
+def logged_call(name, multicall, config):
+ f = config._hooklogfile
+ f.write("%s(**%s)\n" % (name, multicall.kwargs))
+ try:
+ res = config._hooklog_oldperformcall(name=name, multicall=multicall)
+ except:
+ f.write("-> exception")
+ raise
+ f.write("-> %r" % (res,))
+ return res
def pytest_unconfigure(config):
- f = config.pluginmanager.comregistry.logfile
- if f:
- f.close()
- config.pluginmanager.comregistry.logfile = None
+ try:
+ del config.hook.__dict__['_performcall']
+ except KeyError:
+ pass
# ===============================================================================
# plugin tests
Modified: py/dist/py/test/plugin/pytest_monkeypatch.py
==============================================================================
--- py/dist/py/test/plugin/pytest_monkeypatch.py (original)
+++ py/dist/py/test/plugin/pytest_monkeypatch.py Wed Aug 19 18:37:53 2009
@@ -4,7 +4,7 @@
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
to set the environment variable ``ENV1`` and patch the
``os.path.abspath`` function to return a particular value during a test
@@ -20,7 +20,16 @@
The function argument will do the modifications and memorize the
old state. After the test function finished execution all
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/
"""
@@ -57,8 +66,11 @@
self._setitem.insert(0, (dictionary, name, dictionary.get(name, notset)))
dictionary[name] = value
- def setenv(self, name, value):
- self.setitem(os.environ, name, str(value))
+ def setenv(self, name, value, prepend=None):
+ value = str(value)
+ if prepend and name in os.environ:
+ value = value + prepend + os.environ[name]
+ self.setitem(os.environ, name, value)
def finalize(self):
for obj, name, value in self._setattr:
@@ -111,6 +123,16 @@
monkeypatch.finalize()
assert 'XYZ123' not in os.environ
+def test_setenv_prepend():
+ import os
+ monkeypatch = MonkeyPatch()
+ monkeypatch.setenv('XYZ123', 2, prepend="-")
+ assert os.environ['XYZ123'] == "2"
+ monkeypatch.setenv('XYZ123', 3, prepend="-")
+ assert os.environ['XYZ123'] == "3-2"
+ monkeypatch.finalize()
+ assert 'XYZ123' not in os.environ
+
def test_monkeypatch_plugin(testdir):
reprec = testdir.inline_runsource("""
pytest_plugins = 'pytest_monkeypatch',
Added: py/dist/py/test/plugin/pytest_nose.py
==============================================================================
--- (empty file)
+++ py/dist/py/test/plugin/pytest_nose.py Wed Aug 19 18:37:53 2009
@@ -0,0 +1,85 @@
+"""nose-compatibility plugin: allow to run nose test suites natively.
+
+This is an experimental plugin for allowing to run tests written
+in 'nosetests' style with py.test.
+
+Usage
+-------------
+
+type::
+
+ py.test # instead of 'nosetests'
+
+and you should be able to run nose style tests. You will of course
+get py.test style reporting and its feature set.
+
+Issues?
+----------------
+
+If you find issues or have suggestions please run::
+
+ py.test --pastebin=all
+
+and send the resulting URL to a some contact channel.
+
+Known issues
+------------------
+
+- nose-style doctests are not collected and executed correctly,
+ also fixtures don't work.
+
+- no nose-configuration is recognized
+
+"""
+import py
+import inspect
+import sys
+
+def pytest_runtest_makereport(__multicall__, item, call):
+ SkipTest = getattr(sys.modules.get('nose', None), 'SkipTest', None)
+ if SkipTest:
+ if call.excinfo and call.excinfo.errisinstance(SkipTest):
+ # let's substitute the excinfo with a py.test.skip one
+ call2 = call.__class__(lambda: py.test.skip(str(call.excinfo.value)), call.when)
+ call.excinfo = call2.excinfo
+
+def pytest_report_iteminfo(item):
+ # nose 0.11.1 uses decorators for "raises" and other helpers.
+ # for reporting progress by filename we fish for the filename
+ if isinstance(item, py.test.collect.Function):
+ obj = item.obj
+ if hasattr(obj, 'compat_co_firstlineno'):
+ fn = sys.modules[obj.__module__].__file__
+ if fn.endswith(".pyc"):
+ fn = fn[:-1]
+ #assert 0
+ #fn = inspect.getsourcefile(obj) or inspect.getfile(obj)
+ lineno = obj.compat_co_firstlineno
+ return py.path.local(fn), lineno, obj.__module__
+
+def pytest_runtest_setup(item):
+ if isinstance(item, (py.test.collect.Function)):
+ if isinstance(item.parent, py.test.collect.Generator):
+ gen = item.parent
+ if not hasattr(gen, '_nosegensetup'):
+ call_optional(gen.obj, 'setup')
+ if isinstance(gen.parent, py.test.collect.Instance):
+ call_optional(gen.parent.obj, 'setup')
+ gen._nosegensetup = True
+ call_optional(item.obj, 'setup')
+
+def pytest_runtest_teardown(item):
+ if isinstance(item, py.test.collect.Function):
+ call_optional(item.obj, 'teardown')
+ #if hasattr(item.parent, '_nosegensetup'):
+ # #call_optional(item._nosegensetup, 'teardown')
+ # del item.parent._nosegensetup
+
+def pytest_make_collect_report(collector):
+ if isinstance(collector, py.test.collect.Generator):
+ call_optional(collector.obj, 'setup')
+
+def call_optional(obj, name):
+ method = getattr(obj, name, None)
+ if method:
+ method()
Modified: py/dist/py/test/plugin/pytest_pastebin.py
==============================================================================
--- py/dist/py/test/plugin/pytest_pastebin.py (original)
+++ py/dist/py/test/plugin/pytest_pastebin.py Wed Aug 19 18:37:53 2009
@@ -8,7 +8,7 @@
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
for example ``-x`` if you only want to send one particular failure.
@@ -33,9 +33,9 @@
type="choice", choices=['failed', 'all'],
help="send failed|all info to Pocoo pastebin service.")
-def pytest_configure(__call__, config):
+def pytest_configure(__multicall__, config):
import tempfile
- __call__.execute()
+ __multicall__.execute()
if config.option.pastebin == "all":
config._pastebinfile = tempfile.TemporaryFile()
tr = config.pluginmanager.impname2plugin['terminalreporter']
Modified: py/dist/py/test/plugin/pytest_runner.py
==============================================================================
--- py/dist/py/test/plugin/pytest_runner.py (original)
+++ py/dist/py/test/plugin/pytest_runner.py Wed Aug 19 18:37:53 2009
@@ -24,7 +24,7 @@
hook = session.config.hook
rep = hook.pytest__teardown_final(session=session)
if rep:
- hook.pytest__teardown_final_logerror(rep=rep)
+ hook.pytest__teardown_final_logerror(report=rep)
def pytest_make_collect_report(collector):
result = excinfo = None
@@ -72,12 +72,12 @@
rep = TeardownErrorReport(call.excinfo)
return rep
-def pytest_report_teststatus(rep):
- if rep.when in ("setup", "teardown"):
- if rep.failed:
+def pytest_report_teststatus(report):
+ if report.when in ("setup", "teardown"):
+ if report.failed:
# category, shortletter, verbose-word
return "error", "E", "ERROR"
- elif rep.skipped:
+ elif report.skipped:
return "skipped", "s", "SKIPPED"
else:
return "", "", ""
@@ -108,6 +108,13 @@
except:
self.excinfo = py.code.ExceptionInfo()
+ def __repr__(self):
+ if self.excinfo:
+ status = "exception: %s" % str(self.excinfo.value)
+ else:
+ status = "result: %r" % (self.result,)
+ return "<CallInfo when=%r %s>" % (self.when, status)
+
def forked_run_report(item):
# for now, we run setup/teardown in the subprocess
# XXX optionally allow sharing of setup/teardown
Modified: py/dist/py/test/plugin/pytest_terminal.py
==============================================================================
--- py/dist/py/test/plugin/pytest_terminal.py (original)
+++ py/dist/py/test/plugin/pytest_terminal.py Wed Aug 19 18:37:53 2009
@@ -7,7 +7,7 @@
import sys
def pytest_addoption(parser):
- group = parser.getgroup("test process debugging")
+ group = parser.getgroup("debugconfig")
group.addoption('--collectonly',
action="store_true", dest="collectonly",
help="only collect tests, don't execute them."),
@@ -82,7 +82,7 @@
self._tw.sep(sep, title, **markup)
def getcategoryletterword(self, rep):
- res = self.config.hook.pytest_report_teststatus(rep=rep)
+ res = self.config.hook.pytest_report_teststatus(report=rep)
if res:
return res
for cat in 'skipped failed passed ???'.split():
@@ -181,11 +181,11 @@
else:
# ensure that the path is printed before the
# 1st test of a module starts running
- fspath, lineno, msg = self._getreportinfo(item)
- self.write_fspath_result(fspath, "")
- def pytest__teardown_final_logerror(self, rep):
- self.stats.setdefault("error", []).append(rep)
+ self.write_fspath_result(self._getfspath(item), "")
+
+ def pytest__teardown_final_logerror(self, report):
+ self.stats.setdefault("error", []).append(report)
def pytest_runtest_logreport(self, report):
rep = report
@@ -199,8 +199,7 @@
markup = {}
self.stats.setdefault(cat, []).append(rep)
if not self.config.option.verbose:
- fspath, lineno, msg = self._getreportinfo(rep.item)
- self.write_fspath_result(fspath, letter)
+ self.write_fspath_result(self._getfspath(rep.item), letter)
else:
line = self._reportinfoline(rep.item)
if not hasattr(rep, 'node'):
@@ -229,9 +228,9 @@
verinfo = ".".join(map(str, sys.version_info[:3]))
msg = "python: platform %s -- Python %s" % (sys.platform, verinfo)
- if self.config.option.verbose or self.config.option.debug:
- msg += " -- " + str(sys.executable)
+ 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)
if self.config.option.debug or self.config.option.traceconfig:
@@ -241,22 +240,17 @@
if self.config.option.traceconfig:
plugins = []
for plugin in self.config.pluginmanager.comregistry:
- name = plugin.__class__.__name__
- if name.endswith("Plugin"):
- name = name[:-6]
- #if name == "Conftest":
- # XXX get filename
- plugins.append(name)
- else:
- plugins.append(str(plugin))
-
+ name = getattr(plugin, '__name__', None)
+ if name is None:
+ name = plugin.__class__.__name__
+ plugins.append(name)
plugins = ", ".join(plugins)
self.write_line("active plugins: %s" %(plugins,))
for i, testarg in py.builtin.enumerate(self.config.args):
self.write_line("test object %d: %s" %(i+1, testarg))
- def pytest_sessionfinish(self, __call__, session, exitstatus):
- __call__.execute()
+ def pytest_sessionfinish(self, exitstatus, __multicall__):
+ __multicall__.execute()
self._tw.line("")
if exitstatus in (0, 1, 2):
self.summary_errors()
@@ -293,8 +287,13 @@
self.write_line("### Watching: %s" %(rootdir,), bold=True)
def _reportinfoline(self, item):
+ collect_fspath = self._getfspath(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)
if lineno is not None:
lineno += 1
@@ -303,7 +302,7 @@
elif fspath and msg:
line = "%(fspath)s: %(msg)s"
elif fspath and lineno:
- line = "%(fspath)s:%(lineno)s"
+ line = "%(fspath)s:%(lineno)s %(extrapath)s"
else:
line = "[noreportinfo]"
return line % locals() + " "
@@ -327,6 +326,13 @@
item.__reportinfo = reportinfo
return reportinfo
+ def _getfspath(self, item):
+ try:
+ return item.fspath
+ except AttributeError:
+ fspath, lineno, msg = self._getreportinfo(item)
+ return fspath
+
#
# summaries for sessionfinish
#
Modified: py/dist/py/test/plugin/pytest_unittest.py
==============================================================================
--- py/dist/py/test/plugin/pytest_unittest.py (original)
+++ py/dist/py/test/plugin/pytest_unittest.py Wed Aug 19 18:37:53 2009
@@ -55,6 +55,9 @@
if obj is not _dummy:
self._obj = obj
self._sort_value = sort_value
+ if hasattr(self.parent, 'newinstance'):
+ self.parent.newinstance()
+ self.obj = self._getobj()
def runtest(self):
target = self.obj
@@ -87,7 +90,6 @@
def test_setup(testdir):
testpath = testdir.makepyfile(test_two="""
import unittest
- pytest_plugins = "pytest_unittest" # XXX
class MyTestCase(unittest.TestCase):
def setUp(self):
self.foo = 1
@@ -98,6 +100,18 @@
rep = reprec.matchreport("test_setUp")
assert rep.passed
+def test_new_instances(testdir):
+ testpath = testdir.makepyfile("""
+ import unittest
+ class MyTestCase(unittest.TestCase):
+ def test_func1(self):
+ self.x = 2
+ def test_func2(self):
+ assert not hasattr(self, 'x')
+ """)
+ reprec = testdir.inline_run(testpath)
+ reprec.assertoutcome(passed=2)
+
def test_teardown(testdir):
testpath = testdir.makepyfile(test_three="""
import unittest
Modified: py/dist/py/test/plugin/pytest_xfail.py
==============================================================================
--- py/dist/py/test/plugin/pytest_xfail.py (original)
+++ py/dist/py/test/plugin/pytest_xfail.py Wed Aug 19 18:37:53 2009
@@ -19,14 +19,12 @@
import py
-pytest_plugins = ['keyword']
-
-def pytest_runtest_makereport(__call__, item, call):
+def pytest_runtest_makereport(__multicall__, item, call):
if call.when != "call":
return
if hasattr(item, 'obj') and hasattr(item.obj, 'func_dict'):
if 'xfail' in item.obj.func_dict:
- res = __call__.execute(firstresult=True)
+ res = __multicall__.execute()
if call.excinfo:
res.skipped = True
res.failed = res.passed = False
@@ -35,12 +33,11 @@
res.failed = True
return res
-def pytest_report_teststatus(rep):
- """ return shortletter and verbose word. """
- if 'xfail' in rep.keywords:
- if rep.skipped:
+def pytest_report_teststatus(report):
+ if 'xfail' in report.keywords:
+ if report.skipped:
return "xfailed", "x", "xfail"
- elif rep.failed:
+ elif report.failed:
return "xpassed", "P", "xpass"
# called by the terminalreporter instance/plugin
@@ -54,6 +51,9 @@
modpath = rep.item.getmodpath(includemodule=True)
pos = "%s %s:%d: " %(modpath, entry.path, entry.lineno)
reason = rep.longrepr.reprcrash.message
+ i = reason.find("\n")
+ if i != -1:
+ reason = reason[:i]
tr._tw.line("%s %s" %(pos, reason))
xpassed = terminalreporter.stats.get("xpassed")
@@ -90,3 +90,4 @@
"*test_that*",
])
assert result.ret == 1
+
Modified: py/dist/py/test/plugin/test_pytest_capture.py
==============================================================================
--- py/dist/py/test/plugin/test_pytest_capture.py (original)
+++ py/dist/py/test/plugin/test_pytest_capture.py Wed Aug 19 18:37:53 2009
@@ -1,8 +1,7 @@
import py, os, sys
-from py.__.test.plugin.pytest_capture import CaptureManager
+from py.__.test.plugin.pytest_capture import CaptureManager, EncodedFile
class TestCaptureManager:
-
def test_configure_per_fspath(self, testdir):
config = testdir.parseconfig(testdir.tmpdir)
assert config.getvalue("capture") is None
@@ -12,7 +11,7 @@
for name in ('no', 'fd', 'sys'):
sub = testdir.tmpdir.mkdir("dir" + name)
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
@py.test.mark.multi(method=['no', 'fd', 'sys'])
@@ -54,6 +53,42 @@
finally:
capouter.reset()
+ at py.test.mark.multi(method=['fd', 'sys'])
+def test_capturing_unicode(testdir, method):
+ testdir.makepyfile("""
+ # taken from issue 227 from nosetests
+ def test_unicode():
+ import sys
+ print sys.stdout
+ print u'b\\u00f6y'
+ """)
+ result = testdir.runpytest("--capture=%s" % method)
+ result.stdout.fnmatch_lines([
+ "*1 passed*"
+ ])
+
+ at 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")
+ f = p.open('w')
+ pf = EncodedFile(f, "UTF-8")
+ pf.write(u'b\\00f6y\n')
+ pf.write('b\\00f6y\n')
+ pf.close()
+ assert f.closed
+ lines = p.readlines()
+ assert lines[0] == lines[1]
+
def test_collect_capturing(testdir):
p = testdir.makepyfile("""
print "collect %s failure" % 13
Added: py/dist/py/test/plugin/test_pytest_helpconfig.py
==============================================================================
--- (empty file)
+++ py/dist/py/test/plugin/test_pytest_helpconfig.py Wed Aug 19 18:37:53 2009
@@ -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*",
+ ])
+
Added: py/dist/py/test/plugin/test_pytest_nose.py
==============================================================================
--- (empty file)
+++ py/dist/py/test/plugin/test_pytest_nose.py Wed Aug 19 18:37:53 2009
@@ -0,0 +1,87 @@
+import py
+py.test.importorskip("nose")
+
+def test_nose_setup(testdir):
+ p = testdir.makepyfile("""
+ l = []
+
+ def test_hello():
+ assert l == [1]
+ def test_world():
+ assert l == [1,2]
+ test_hello.setup = lambda: l.append(1)
+ test_hello.teardown = lambda: l.append(2)
+ """)
+ result = testdir.runpytest(p, '-p', 'nose')
+ result.stdout.fnmatch_lines([
+ "*2 passed*"
+ ])
+
+def test_nose_test_generator_fixtures(testdir):
+ p = testdir.makepyfile("""
+ # taken from nose-0.11.1 unit_tests/test_generator_fixtures.py
+ from nose.tools import eq_
+ called = []
+
+ def outer_setup():
+ called.append('outer_setup')
+
+ def outer_teardown():
+ called.append('outer_teardown')
+
+ def inner_setup():
+ called.append('inner_setup')
+
+ def inner_teardown():
+ called.append('inner_teardown')
+
+ def test_gen():
+ called[:] = []
+ for i in range(0, 5):
+ yield check, i
+
+ def check(i):
+ expect = ['outer_setup']
+ for x in range(0, i):
+ expect.append('inner_setup')
+ expect.append('inner_teardown')
+ expect.append('inner_setup')
+ eq_(called, expect)
+
+
+ test_gen.setup = outer_setup
+ test_gen.teardown = outer_teardown
+ check.setup = inner_setup
+ check.teardown = inner_teardown
+
+ class TestClass(object):
+ def setup(self):
+ print "setup called in", self
+ self.called = ['setup']
+
+ def teardown(self):
+ print "teardown called in", self
+ eq_(self.called, ['setup'])
+ self.called.append('teardown')
+
+ def test(self):
+ print "test called in", self
+ for i in range(0, 5):
+ yield self.check, i
+
+ def check(self, i):
+ print "check called in", self
+ expect = ['setup']
+ #for x in range(0, i):
+ # expect.append('setup')
+ # expect.append('teardown')
+ #expect.append('setup')
+ eq_(self.called, expect)
+
+ """)
+ result = testdir.runpytest(p, '-p', 'nose')
+ result.stdout.fnmatch_lines([
+ "*10 passed*"
+ ])
+
+
Modified: py/dist/py/test/plugin/test_pytest_runner.py
==============================================================================
--- py/dist/py/test/plugin/test_pytest_runner.py (original)
+++ py/dist/py/test/plugin/test_pytest_runner.py Wed Aug 19 18:37:53 2009
@@ -271,3 +271,13 @@
"*1 failed*"
])
+def test_callinfo():
+ ci = runner.CallInfo(lambda: 0, '123')
+ assert ci.when == "123"
+ assert ci.result == 0
+ assert "result" in repr(ci)
+ ci = runner.CallInfo(lambda: 0/0, '123')
+ assert ci.when == "123"
+ assert not hasattr(ci, 'result')
+ assert ci.excinfo
+ assert "exc" in repr(ci)
Modified: py/dist/py/test/plugin/test_pytest_runner_xunit.py
==============================================================================
--- py/dist/py/test/plugin/test_pytest_runner_xunit.py (original)
+++ py/dist/py/test/plugin/test_pytest_runner_xunit.py Wed Aug 19 18:37:53 2009
@@ -125,18 +125,12 @@
def test_method_setup_uses_fresh_instances(testdir):
reprec = testdir.inline_runsource("""
class TestSelfState1:
- def __init__(self):
- self.hello = 42
+ memory = []
def test_hello(self):
- self.world = 23
+ self.memory.append(self)
+
def test_afterhello(self):
- assert not hasattr(self, 'world')
- assert self.hello == 42
- class TestSelfState2:
- def test_hello(self):
- self.world = 10
- def test_world(self):
- assert not hasattr(self, 'world')
+ assert self != self.memory[0]
""")
- reprec.assertoutcome(passed=4, failed=0)
+ reprec.assertoutcome(passed=2, failed=0)
Modified: py/dist/py/test/plugin/test_pytest_terminal.py
==============================================================================
--- py/dist/py/test/plugin/test_pytest_terminal.py (original)
+++ py/dist/py/test/plugin/test_pytest_terminal.py Wed Aug 19 18:37:53 2009
@@ -209,10 +209,6 @@
item = testdir.getitem("def test_func(): pass")
tr = TerminalReporter(item.config, file=linecomp.stringio)
item.config.pluginmanager.register(tr)
- tr.config.hook.pytest_itemstart(item=item)
- linecomp.assert_contains_lines([
- "*ABCDE "
- ])
tr.config.option.verbose = True
tr.config.hook.pytest_itemstart(item=item)
linecomp.assert_contains_lines([
@@ -227,16 +223,35 @@
item.config.pluginmanager.register(Plugin())
tr = TerminalReporter(item.config, file=linecomp.stringio)
item.config.pluginmanager.register(tr)
- tr.config.hook.pytest_itemstart(item=item)
- linecomp.assert_contains_lines([
- "*FGHJ "
- ])
tr.config.option.verbose = True
tr.config.hook.pytest_itemstart(item=item)
linecomp.assert_contains_lines([
"*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):
p = testdir.makepyfile("""
raise KeyboardInterrupt
Modified: py/dist/py/test/pluginmanager.py
==============================================================================
--- py/dist/py/test/pluginmanager.py (original)
+++ py/dist/py/test/pluginmanager.py Wed Aug 19 18:37:53 2009
@@ -16,10 +16,9 @@
if comregistry is None:
comregistry = py._com.Registry()
self.comregistry = comregistry
- self.MultiCall = self.comregistry.MultiCall
self.impname2plugin = {}
- self.hook = py._com.Hooks(
+ self.hook = py._com.HookRelay(
hookspecs=hookspec,
registry=self.comregistry)
@@ -135,15 +134,16 @@
fail = True
else:
method_args = getargs(method)
- if '__call__' in method_args:
- method_args.remove('__call__')
+ if '__multicall__' in method_args:
+ method_args.remove('__multicall__')
hook = hooks[name]
hookargs = getargs(hook)
- for arg, hookarg in zip(method_args, hookargs):
- if arg != hookarg:
- Print("argument mismatch: %r != %r" %(arg, hookarg))
- Print("actual : %s" %(formatdef(method)))
- Print("required:", formatdef(hook))
+ for arg in method_args:
+ if arg not in hookargs:
+ Print("argument %r not available" %(arg, ))
+ Print("actual definition: %s" %(formatdef(method)))
+ Print("available hook arguments: %s" %
+ ", ".join(hookargs))
fail = True
break
#if not fail:
@@ -166,20 +166,24 @@
return self.hook.pytest_internalerror(excrepr=excrepr)
def do_addoption(self, parser):
- methods = self.comregistry.listattr("pytest_addoption", reverse=True)
- mc = py._com.MultiCall(methods, parser=parser)
+ mname = "pytest_addoption"
+ methods = self.comregistry.listattr(mname, reverse=True)
+ mc = py._com.MultiCall(methods, {'parser': parser})
mc.execute()
def pytest_plugin_registered(self, plugin):
if hasattr(self, '_config'):
- self.call_plugin(plugin, "pytest_addoption", parser=self._config._parser)
- self.call_plugin(plugin, "pytest_configure", config=self._config)
+ self.call_plugin(plugin, "pytest_addoption",
+ {'parser': self._config._parser})
+ self.call_plugin(plugin, "pytest_configure",
+ {'config': self._config})
#dic = self.call_plugin(plugin, "pytest_namespace")
#self._updateext(dic)
- def call_plugin(self, plugin, methname, **kwargs):
- return self.MultiCall(self.listattr(methname, plugins=[plugin]),
- **kwargs).execute(firstresult=True)
+ def call_plugin(self, plugin, methname, kwargs):
+ return py._com.MultiCall(
+ methods=self.listattr(methname, plugins=[plugin]),
+ kwargs=kwargs, firstresult=True).execute()
def _updateext(self, dic):
if dic:
@@ -200,9 +204,6 @@
config.hook.pytest_unconfigure(config=config)
config.pluginmanager.unregister(self)
-class Ext:
- """ namespace for extension objects. """
-
#
# XXX old code to automatically load classes
#
@@ -232,8 +233,7 @@
def isgenerichook(name):
return name == "pytest_plugins" or \
- name.startswith("pytest_funcarg__") or \
- name.startswith("pytest_option_")
+ name.startswith("pytest_funcarg__")
def getargs(func):
args = py.std.inspect.getargs(func.func_code)[0]
Modified: py/dist/py/test/pycollect.py
==============================================================================
--- py/dist/py/test/pycollect.py (original)
+++ py/dist/py/test/pycollect.py Wed Aug 19 18:37:53 2009
@@ -123,8 +123,7 @@
collector=self, name=name, obj=obj)
if res is not None:
return res
- if (self.classnamefilter(name)) and \
- py.std.inspect.isclass(obj):
+ if self._istestclasscandidate(name, obj):
res = self._deprecated_join(name)
if res is not None:
return res
@@ -139,14 +138,25 @@
else:
return self._genfunctions(name, obj)
+ def _istestclasscandidate(self, name, obj):
+ if self.classnamefilter(name) and \
+ py.std.inspect.isclass(obj):
+ if hasinit(obj):
+ # XXX WARN
+ return False
+ return True
+
+
def _genfunctions(self, name, funcobj):
module = self.getparent(Module).obj
# due to _buildname2items funcobj is the raw function, we need
# to work to get at the class
clscol = self.getparent(Class)
cls = clscol and clscol.obj or None
- metafunc = funcargs.Metafunc(funcobj, config=self.config, cls=cls, module=module)
- gentesthook = self.config.hook.pytest_generate_tests.clone(extralookup=module)
+ metafunc = funcargs.Metafunc(funcobj, config=self.config,
+ cls=cls, module=module)
+ gentesthook = self.config.hook._makecall(
+ "pytest_generate_tests", extralookup=module)
gentesthook(metafunc=metafunc)
if not metafunc._calls:
return self.Function(name, parent=self)
@@ -371,3 +381,9 @@
def __ne__(self, other):
return not self == other
+
+def hasinit(obj):
+ init = getattr(obj, '__init__', None)
+ if init:
+ if not isinstance(init, type(object.__init__)):
+ return True
Modified: py/dist/py/test/testing/acceptance_test.py
==============================================================================
--- py/dist/py/test/testing/acceptance_test.py (original)
+++ py/dist/py/test/testing/acceptance_test.py Wed Aug 19 18:37:53 2009
@@ -1,7 +1,5 @@
import py
-EXPECTTIMEOUT=10.0
-
class TestGeneralUsage:
def test_config_error(self, testdir):
testdir.makeconftest("""
@@ -67,3 +65,12 @@
"E ImportError: No module named does_not_work",
])
assert result.ret == 1
+
+ def test_not_collectable_arguments(self, testdir):
+ p1 = testdir.makepyfile("")
+ p2 = testdir.makefile(".pyc", "123")
+ result = testdir.runpytest(p1, p2)
+ assert result.ret != 0
+ assert result.stderr.fnmatch_lines([
+ "*ERROR: can't collect: %s" %(p2,)
+ ])
Modified: py/dist/py/test/testing/test_collect.py
==============================================================================
--- py/dist/py/test/testing/test_collect.py (original)
+++ py/dist/py/test/testing/test_collect.py Wed Aug 19 18:37:53 2009
@@ -145,7 +145,7 @@
names = [x.name for x in col.collect()]
assert names == ["dir1", "dir2", "test_one.py", "test_two.py", "x"]
-class TestCollectPluginHooks:
+class TestCollectPluginHookRelay:
def test_pytest_collect_file(self, testdir):
tmpdir = testdir.tmpdir
wascalled = []
@@ -179,6 +179,18 @@
names = [rep.collector.name for rep in colreports]
assert names.count("hello") == 1
+class TestPrunetraceback:
+ def test_collection_error(self, testdir):
+ p = testdir.makepyfile("""
+ import not_exists
+ """)
+ result = testdir.runpytest(p)
+ assert "__import__" not in result.stdout.str(), "too long traceback"
+ result.stdout.fnmatch_lines([
+ "*ERROR during collection*",
+ ">*import not_exists*"
+ ])
+
class TestCustomConftests:
def test_non_python_files(self, testdir):
testdir.makepyfile(conftest="""
Modified: py/dist/py/test/testing/test_config.py
==============================================================================
--- py/dist/py/test/testing/test_config.py (original)
+++ py/dist/py/test/testing/test_config.py Wed Aug 19 18:37:53 2009
@@ -42,7 +42,7 @@
def test_parser_addoption_default_conftest(self, testdir, monkeypatch):
import os
- testdir.makeconftest("pytest_option_verbose=True")
+ testdir.makeconftest("option_verbose=True")
config = testdir.parseconfig()
assert config.option.verbose
Deleted: /py/dist/py/test/testing/test_install.py
==============================================================================
--- /py/dist/py/test/testing/test_install.py Wed Aug 19 18:37:53 2009
+++ (empty file)
@@ -1,16 +0,0 @@
-import py
-
-def test_make_sdist_and_run_it(capfd, py_setup, venv):
- try:
- sdist = py_setup.make_sdist(venv.path)
- venv.easy_install(str(sdist))
- gw = venv.makegateway()
- ch = gw.remote_exec("import py ; channel.send(py.__version__)")
- version = ch.receive()
- assert version == py.__version__
- except KeyboardInterrupt:
- raise
- except:
- print capfd.readouterr()
- raise
- capfd.close()
Modified: py/dist/py/test/testing/test_pluginmanager.py
==============================================================================
--- py/dist/py/test/testing/test_pluginmanager.py (original)
+++ py/dist/py/test/testing/test_pluginmanager.py Wed Aug 19 18:37:53 2009
@@ -4,7 +4,7 @@
class TestBootstrapping:
def test_consider_env_fails_to_import(self, monkeypatch):
pluginmanager = PluginManager()
- monkeypatch.setitem(os.environ, 'PYTEST_PLUGINS', 'nonexistingmodule')
+ monkeypatch.setenv('PYTEST_PLUGINS', 'nonexisting', prepend=",")
py.test.raises(ImportError, "pluginmanager.consider_env()")
def test_preparse_args(self):
@@ -50,7 +50,7 @@
plugin = py.test.config.pluginmanager.getplugin('x500')
assert plugin is not None
""")
- monkeypatch.setitem(os.environ, 'PYTEST_PLUGINS', 'pytest_x500')
+ monkeypatch.setenv('PYTEST_PLUGINS', 'pytest_x500', prepend=",")
result = testdir.runpytest(p)
assert result.ret == 0
extra = result.stdout.fnmatch_lines(["*1 passed in*"])
@@ -185,7 +185,7 @@
assert hello == "world"
""")
result = testdir.runpytest(p)
- assert result.stdout.fnmatch_lines([
+ result.stdout.fnmatch_lines([
"*1 passed*"
])
@@ -222,10 +222,6 @@
config.pluginmanager.register(A())
assert len(l) == 2
- def test_MultiCall(self):
- pp = PluginManager()
- assert hasattr(pp, 'MultiCall')
-
# lower level API
def test_listattr(self):
@@ -247,3 +243,12 @@
assert list(methods) == ['pytest_hello', 'pytest_world']
methods = py.builtin.sorted(collectattr(B()))
assert list(methods) == ['pytest_hello', 'pytest_world']
+
+ at py.test.mark.xfail
+def test_namespace_has_default_and_env_plugins(testdir):
+ p = testdir.makepyfile("""
+ import py
+ py.test.mark
+ """)
+ result = testdir.runpython(p)
+ assert result.ret == 0
Modified: py/dist/py/test/testing/test_pycollect.py
==============================================================================
--- py/dist/py/test/testing/test_pycollect.py (original)
+++ py/dist/py/test/testing/test_pycollect.py Wed Aug 19 18:37:53 2009
@@ -39,6 +39,19 @@
modcol = testdir.getmodulecol("pytest_plugins='xasdlkj',")
py.test.raises(ImportError, "modcol.obj")
+class TestClass:
+ def test_class_with_init_not_collected(self, testdir):
+ modcol = testdir.getmodulecol("""
+ class TestClass1:
+ def __init__(self):
+ pass
+ class TestClass2(object):
+ def __init__(self):
+ pass
+ """)
+ l = modcol.collect()
+ assert len(l) == 0
+
class TestDisabled:
def test_disabled_module(self, testdir):
modcol = testdir.getmodulecol("""
Modified: py/dist/setup.py
==============================================================================
--- py/dist/setup.py (original)
+++ py/dist/setup.py Wed Aug 19 18:37:53 2009
@@ -31,7 +31,7 @@
name='py',
description='py.test and pylib: advanced testing tool and networking lib',
long_description = long_description,
- version= trunk or '1.0.0',
+ version= trunk or '1.0.1',
url='http://pylib.org',
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
@@ -105,8 +105,6 @@
'py.xmlobj.testing'],
package_data={'py': ['LICENSE',
'bin/_findpy.py',
- 'bin/_genscripts.py',
- 'bin/gendoc.py',
'bin/py.cleanup',
'bin/py.countloc',
'bin/py.lookup',
More information about the pytest-commit
mailing list