[Python-modules-commits] [tox] 13/69: Import tox_1.5.0.orig.tar.gz

Barry Warsaw barry at moszumanska.debian.org
Fri Sep 5 23:26:24 UTC 2014


This is an automated email from the git hooks/post-receive script.

barry pushed a commit to branch master
in repository tox.

commit fa3e42ce924fc77fe9f9e65bca75b955a1e5e17c
Author: Barry Warsaw <barry at python.org>
Date:   Fri Sep 5 17:08:05 2014 -0400

    Import tox_1.5.0.orig.tar.gz
---
 .hg_archival.txt                          |   4 -
 .hgignore                                 |  16 --
 .hgtags                                   |  12 -
 CHANGELOG                                 |  75 +++++++
 CONTRIBUTORS                              |   8 +-
 ISSUES.txt                                |  75 +++++++
 LICENSE                                   |  24 +-
 PKG-INFO                                  |  52 +++++
 README.txt => README.rst                  |  11 +-
 doc/Makefile                              |   2 +-
 doc/announce/release-1.4.3.txt            |  97 ++++++++
 doc/announce/release-1.4.txt              |   2 +-
 doc/conf.py                               |   4 +-
 doc/config-v2.txt                         | 292 ++++++++++++++++++++++++
 doc/config.txt                            |  29 ++-
 doc/example/basic.txt                     |  17 ++
 doc/example/jenkins.txt                   |   2 -
 doc/example/pytest.txt                    |  28 ++-
 doc/index.txt                             |  22 +-
 doc/install.txt                           |   4 +-
 doc/links.txt                             |  26 +--
 doc/support.txt                           |  16 +-
 setup.cfg                                 |   5 +
 setup.py                                  |  58 ++---
 tests/conftest.py                         | 289 +-----------------------
 tests/test_config.py                      | 167 ++++++++++++--
 tests/test_quickstart.py                  | 362 ++++++++++++++++++++++++++++++
 tests/test_venv.py                        | 113 ++++++++--
 tests/test_z_cmdline.py                   |  39 +++-
 tox.egg-info/PKG-INFO                     |  52 +++++
 tox.egg-info/SOURCES.txt                  |  57 +++++
 tox.egg-info/dependency_links.txt         |   1 +
 tox.egg-info/entry_points.txt             |   4 +
 tox.egg-info/requires.txt                 |   2 +
 tox.egg-info/top_level.txt                |   1 +
 tox.egg-info/zip-safe                     |   1 +
 tox.ini                                   |  17 +-
 tox/__init__.py                           |   2 +-
 tox/_cmdline.py                           |  84 ++++---
 tox/_config.py                            | 216 ++++++++++++------
 tests/conftest.py => tox/_pytestplugin.py |  26 +--
 tox/_quickstart.py                        | 266 ++++++++++++++++++++++
 tox/_venv.py                              | 141 +++++++-----
 toxbootstrap.py                           |   9 +-
 44 files changed, 2080 insertions(+), 650 deletions(-)

diff --git a/.hg_archival.txt b/.hg_archival.txt
deleted file mode 100644
index 82b89ce..0000000
--- a/.hg_archival.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-repo: bbc71705ea25a9ace4fd51f5a8d15abcaea7d684
-node: 668f66e4781b0beae509db8125dc02218f6efe4e
-branch: default
-tag: 1.4.2
diff --git a/.hgignore b/.hgignore
deleted file mode 100644
index cf24d86..0000000
--- a/.hgignore
+++ /dev/null
@@ -1,16 +0,0 @@
-
-syntax:glob
-*.pyc
-*.pyo
-*.swp
-*.html
-*.class
-*.orig
-*.rej
-*~
-
-build
-dist
-doc/_build/
-tox.egg-info
-.tox
diff --git a/.hgtags b/.hgtags
deleted file mode 100644
index 10f5e4a..0000000
--- a/.hgtags
+++ /dev/null
@@ -1,12 +0,0 @@
-4de489705645915e7f6147e60e64eac7750e48d9 0.5
-cdc2ffbb162ac897045542b73bd5b3c6f3e53290 0.6
-14c629f52d957273514b17bb8f774ed27c03e9cf 0.8
-e1ffa42a5513704fbd4b3e20fea549acff228d90 0.9
-53885d6bf89e044323cc0ffdb8658124c644d337 1.0
-53885d6bf89e044323cc0ffdb8658124c644d337 1.0
-b4db03a77e9e6f4c7e875c40886de9ceaa6baceb 1.0
-3f52ff320a6e5e1f9a14b5c9ebbf6bc521ef59b6 1.1
-e68d4bfd1af32feae87bf01db11792ce0d634975 1.2
-3ee108c91b2fdcd984026c8c488da846377a6a9c 1.3
-d5dbb01fc0eb73f7eca74842d1ce02554552b0a3 1.4
-3a68408fa3a210c2a2e52189e16f5ae6dfed287d 1.4.1
diff --git a/CHANGELOG b/CHANGELOG
old mode 100755
new mode 100644
index b703b8e..3cce0bf
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,78 @@
+1.5.0
+-----------------
+
+- fix issue104: use setuptools by default, instead of distribute,
+  now that setuptools has distribute merged.
+
+- make sure test commands are searched first in the virtualenv 
+
+- re-fix issue2 - add whitelist_externals to be used in ``[testenv*]``
+  sections, allowing to avoid warnings for commands such as ``make``,
+  used from the commands value.
+
+- fix issue97 - allow substitutions to reference from other sections
+  (thanks Krisztian Fekete)
+
+- fix issue92 - fix {envsitepackagesdir} to actually work again
+
+- show (test) command that is being executed, thanks 
+  Lukasz Balcerzak
+
+- re-license tox to MIT license
+
+- depend on virtualenv-1.9.1 
+
+- rename README.txt to README.rst to make bitbucket happier
+
+
+1.4.3
+-----------------
+
+- use pip-script.py instead of pip.exe on win32 to avoid the lock exe
+  file on execution issue (thanks Philip Thiem)
+
+- introduce -l|--listenv option to list configured environments
+  (thanks  Lukasz Balcerzak)
+
+- fix downloadcache determination to work according to docs: Only
+  make pip use a download cache if PIP_DOWNLOAD_CACHE or a 
+  downloadcache=PATH testenv setting is present. (The ENV setting
+  takes precedence)
+
+- fix issue84 - pypy on windows creates a bin not a scripts venv directory
+  (thanks Lukasz Balcerzak)
+
+- experimentally introduce --installpkg=PATH option to install a package
+  rather than create/install an sdist package.  This will still require
+  and use tox.ini and tests from the current working dir (and not from the
+  remote package).
+
+- substitute {envsitepackagesdir} with the package installation
+  directory (closes #72) (thanks g2p)
+
+- issue #70 remove PYTHONDONTWRITEBYTECODE workaround now that
+  virtualenv behaves properly (thanks g2p)
+
+- merged tox-quickstart command, contributed by Marc Abramowitz, which
+  generates a default tox.ini after asking a few questions
+
+- fix #48 - win32 detection of pypy and other interpreters that are on PATH
+  (thanks Gustavo Picon)
+
+- fix grouping of index servers, it is now done by name instead of 
+  indexserver url, allowing to use it to separate dependencies
+  into groups even if using the same default indexserver.
+
+- look for "tox.ini" files in parent dirs of current dir (closes #34)
+
+- the "py" environment now by default uses the current interpreter
+  (sys.executable) make tox' own setup.py test execute tests with it
+  (closes #46)
+
+- change tests to not rely on os.path.expanduser (closes #60),
+  also make mock session return args[1:] for more precise checking (closes #61)
+  thanks to Barry Warsaw for both.
+
 1.4.2
 -----------------
 
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 74a1047..a6f2d71 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1,6 +1,12 @@
 
-contributions (under the MIT license):
+contributions:
 
+Krisztian Fekete
+Marc Abramowitz
 Sridhar Ratnakumar
+Barry Warsaw
 Chris Rose
 Jannis Leidl
+Ronny Pfannschmidt
+Lukasz Balcerzak 
+Philip Thiem
diff --git a/ISSUES.txt b/ISSUES.txt
index 08e89b5..4b05dff 100644
--- a/ISSUES.txt
+++ b/ISSUES.txt
@@ -1,3 +1,76 @@
+introduce package and setup.py less sdist creation
+-----------------------------------------------------------
+
+Example sections for tox itself::
+
+    [pkgdef] 
+    basename = pytest
+    description = virtualenv-based automation of test activities
+    authors = holger krekel <holger at merlinux.eu>
+    url = http://tox.testrun.org
+    entry_points = console_scripts: tox=tox:cmdline
+    requires = py
+    packages = 
+    preuploadenvs = sphinx 
+
+    classifiers=
+        Development Status :: 6 - Mature
+        Intended Audience :: Developers
+        License :: OSI Approved :: MIT License
+        Topic :: Software Development :: Testing
+        Topic :: Software Development :: Libraries
+        Topic :: Utilities
+
+This would generate three different packages:
+
+- the main one containing the app with the specified description, etc.
+  It has a test-requires pointing to the test package,
+  which classifiers
+- the test package only containing the tests and setup.py
+  depending on the main package and all requirements collected from the
+  testenv
+- the doc package containing generated html and txt files
+  (to be installable via a setup.py as well?)
+
+Here is what happens when tox is invoked now:
+
+- version gets auto-incremented (in setup.py and $PACKAGE/__init__.py files)
+- main setup.py generated, files copied, sdist generated
+- test setup.py generated, files copied, sdist generated
+- doc setup.py generated, doc environment run, files copied, sdist generated
+
+- if --upload is specified, all packages are uploaded under 
+  their respective names:
+  tox-VER
+  tests-tox-VER
+  docs-tox-VER
+
+- tox --sync creates a test result file for the tests-tox-VER run
+  and uploads it to testrun.org -- .tox/projectkeys contains a file that
+  was created by visiting testrun.org and registering/logging in.
+
+- download toxslave and execute it:
+
+    toxslave --userkey=... [--project tox]
+
+  which will query testrun.org for outstanding testruns
+  [for the tox project], download packages, execute them 
+  and report back to the server
+
+merge tox and detox?
+----------------------------------------------------------------
+
+maybe it's time to merge it?
+
+http://lists.idyll.org/pipermail/testing-in-python/2012-October/005205.html
+pyc files / test distributions
+-----------------------------------------------------------
+
+investigate pyc cleaning, see
+
+http://lists.idyll.org/pipermail/testing-in-python/2012-October/005205.html
+
+
 allow config overlays
 -----------------------------------------------------------
 
@@ -56,6 +129,8 @@ look into ways to support integration of tox with travis.
 - generate .travis.yml from tox.ini
 - generate tox.ini from .travis.yml
 
+For the last two, take a look at http://pypi.python.org/pypi/panci/
+
 allow user-specific python interpreters
 ------------------------------------------------
 
diff --git a/LICENSE b/LICENSE
index 9246a20..97aff5c 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,10 +1,20 @@
-The execnet package is released under the provisions of the Gnu Public
-License (GPL), version 2 or later.  
 
-See http://www.fsf.org/licensing/licenses/ for more information.
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+ 
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
 
-If you have questions and/or want to use parts of 
-the code under a different license than the GPL 
-please contact me.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-holger krekel, May 2011, holger at merlinux eu 
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..3335f00
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,52 @@
+Metadata-Version: 1.1
+Name: tox
+Version: 1.5.0
+Summary: virtualenv-based automation of test activities
+Home-page: http://tox.testrun.org/
+Author: holger krekel
+Author-email: holger at merlinux.eu
+License: http://opensource.org/licenses/MIT
+Description: 
+        What is Tox?
+        --------------------
+        
+        Tox as is a generic virtualenv_ management and test command line tool you can use for:
+        
+        * checking your package installs correctly with different Python versions and
+          interpreters
+        
+        * running your tests in each of the environments, configuring your test tool of choice
+        
+        * acting as a frontend to Continuous Integration servers, greatly
+          reducing boilerplate and merging CI and shell-based testing.
+        
+        For more information and the repository please checkout:
+        
+        - homepage: http://tox.testrun.org
+        
+        - repository: https://bitbucket.org/hpk42/tox
+        
+        have fun,
+        
+        
+        have fun,
+        
+        holger krekel, May 2013
+        
+        
+Platform: unix
+Platform: linux
+Platform: osx
+Platform: cygwin
+Platform: win32
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: POSIX
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Topic :: Software Development :: Testing
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Topic :: Utilities
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
diff --git a/README.txt b/README.rst
similarity index 72%
rename from README.txt
rename to README.rst
index ea017dc..f53cef3 100644
--- a/README.txt
+++ b/README.rst
@@ -12,11 +12,16 @@ Tox as is a generic virtualenv_ management and test command line tool you can us
 * acting as a frontend to Continuous Integration servers, greatly
   reducing boilerplate and merging CI and shell-based testing.
 
-For more information, docs and many examples please checkout:
+For more information and the repository please checkout:
+
+- homepage: http://tox.testrun.org
+
+- repository: https://bitbucket.org/hpk42/tox
+
+have fun,
 
-    http://tox.testrun.org
 
 have fun,
 
-holger krekel, May 2012
+holger krekel, May 2013
 
diff --git a/doc/Makefile b/doc/Makefile
index 1142b1c..77b2083 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -37,7 +37,7 @@ clean:
 	-rm -rf $(BUILDDIR)/*
 
 install: clean html 
-	@rsync -avz $(BUILDDIR)/html/ testrun.org:/www/tox.testrun.org/latest
+	@rsync -avz $(BUILDDIR)/html/ testrun.org:/www/testrun.org/tox/latest
     #latexpdf
 	#@scp $(BUILDDIR)/latex/*.pdf testrun.org:www-tox/latest
 
diff --git a/doc/announce/release-1.4.3.txt b/doc/announce/release-1.4.3.txt
new file mode 100644
index 0000000..ca0bb19
--- /dev/null
+++ b/doc/announce/release-1.4.3.txt
@@ -0,0 +1,97 @@
+tox 1.4.3: the Python virtualenv-based testing automatizer
+=============================================================================
+
+tox 1.4.3 fixes some bugs and introduces a new script and two new options:
+
+- "tox-quickstart" - run this script, answer a few questions, and
+  get a tox.ini created for you (thanks Marc Abramowitz)
+
+- "tox -l" lists configured environment names (thanks Lukasz Balcerzak)
+
+- (experimental) "--installpkg=localpath" option which will skip the
+  sdist-creation of a package and instead install the given localpath package.
+
+- use pip-script.py instead of pip.exe on win32 to avoid windows locking
+  the .exe
+
+Note that the sister project "detox" should continue to work - it's a 
+separately released project which drives tox test runs on multiple CPUs
+in parallel.
+
+More documentation:
+
+    http://tox.testrun.org/
+
+Installation:
+
+    pip install -U tox
+
+repository hosting and issue tracking on bitbucket:
+
+    https://bitbucket.org/hpk42/tox
+
+
+What is tox?
+----------------
+
+tox standardizes and automates tedious python driven test activities
+driven from a simple ``tox.ini`` file, including:
+
+* creation and management of different virtualenv environments 
+  with different Python interpreters
+* packaging and installing your package into each of them
+* running your test tool of choice, be it nose, py.test or unittest2 or other tools such as "sphinx" doc checks
+* testing dev packages against each other without needing to upload to PyPI
+
+best,
+Holger Krekel
+
+
+CHANGELOG
+================
+
+1.4.3 (compared to 1.4.2)
+--------------------------------
+
+- introduce -l|--listenv option to list configured environments
+  (thanks  Lukasz Balcerzak)
+
+- fix downloadcache determination to work according to docs: Only
+  make pip use a download cache if PIP_DOWNLOAD_CACHE or a 
+  downloadcache=PATH testenv setting is present. (The ENV setting
+  takes precedence)
+
+- fix issue84 - pypy on windows creates a bin not a scripts venv directory
+  (thanks Lukasz Balcerzak)
+
+- experimentally introduce --installpkg=PATH option to install a package rather than
+  create/install an sdist package.  This will still require and use
+  tox.ini and tests from the current working dir (and not from the remote
+  package).
+
+- substitute {envsitepackagesdir} with the package installation directory (closes #72)
+  (thanks g2p)
+
+- issue #70 remove PYTHONDONTWRITEBYTECODE workaround now that
+  virtualenv behaves properly (thanks g2p)
+
+- merged tox-quickstart command, contributed by Marc Abramowitz, which
+  generates a default tox.ini after asking a few questions
+
+- fix #48 - win32 detection of pypy and other interpreters that are on PATH
+  (thanks Gustavo Picon)
+
+- fix grouping of index servers, it is now done by name instead of 
+  indexserver url, allowing to use it to separate dependencies
+  into groups even if using the same default indexserver.
+
+- look for "tox.ini" files in parent dirs of current dir (closes #34)
+
+- the "py" environment now by default uses the current interpreter
+  (sys.executable) make tox' own setup.py test execute tests with it
+  (closes #46)
+
+- change tests to not rely on os.path.expanduser (closes #60),
+  also make mock session return args[1:] for more precise checking (closes #61)
+  thanks to Barry Warszaw for both.
+
diff --git a/doc/announce/release-1.4.txt b/doc/announce/release-1.4.txt
index 3863c2a..5565bb3 100644
--- a/doc/announce/release-1.4.txt
+++ b/doc/announce/release-1.4.txt
@@ -4,7 +4,7 @@ tox 1.4: the virtualenv-based test run automatizer
 I am happy to announce tox 1.4 which brings:
 
 - improvements with configuration file syntax, now allowing re-using
-  selected settings across config file sections. see http://bit.ly/Ly3K4f
+  selected settings across config file sections. see http://testrun.org/tox/latest/config.html#substition-for-values-from-other-sections
 
 - terminal reporting was simplified and streamlined.  Now with
   verbosity==0 (the default), less information will be shown
diff --git a/doc/conf.py b/doc/conf.py
index ac558b4..f643b48 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -41,14 +41,14 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'tox'
-copyright = u'2011, holger krekel and others'
+copyright = u'2013, holger krekel and others'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
 # The short X.Y version.
-release = version = "1.4-3"
+release = version = "1.5.0"
 # The full version, including alpha/beta/rc tags.
 
 # The language for content autogenerated by Sphinx. Refer to documentation
diff --git a/doc/config-v2.txt b/doc/config-v2.txt
new file mode 100644
index 0000000..cf4cf3b
--- /dev/null
+++ b/doc/config-v2.txt
@@ -0,0 +1,292 @@
+V2: new tox multi-dimensional, platform-specific configuration
+--------------------------------------------------------------------
+
+.. note::
+   
+   This is a draft document sketching a to-be-done implementation.
+   It does not fully specify each change yet but should give a good
+   idea of where things are heading.  For feedback, mail the 
+   testing-in-python mailing list or open a pull request on 
+   https://bitbucket.org/hpk42/tox/src/84d8cf3c2a95fefd874f22c8b2d257e94365472f/doc/config-v2.txt?at=default
+ 
+**Abstract**: Adding multi-dimensional configuration, platform-specification
+and multiple installers to tox.ini.
+ 
+**Target audience**: Developers using or wanting to use tox for testing
+their python projects.
+ 
+Issues with current tox (1.4) configuration
+------------------------------------------------
+
+Tox is used as a tool for creating and managing virtualenv environments
+and running tests in them. As of tox-1.4 there are some issues frequently
+coming up with its configuration language:
+
+- there is no way to instruct tox to parametrize testenv specifications 
+  other than to list all combinations by specifying a ``[testenv:...]``
+  section for each combination. Examples of real life situations 
+  arising from this:
+
+  * http://code.larlet.fr/django-rest-framework/src/eed0f39a7e45/tox.ini
+  
+  * https://bitbucket.org/tabo/django-treebeard/src/93b579395a9c/tox.ini
+
+- there is no way to have platform specific settings other than to
+  define specific testenvs and invoke tox with a platform-specific 
+  testenv list.
+
+- there is no way to specify the platforms against which a project
+  shall successfully run.
+
+- tox always uses pip for installing packages currently.  This has
+  several issues:
+
+  - no way to check if installing via easy_install works
+  - no installs of packages with compiled c-extensions (win32 standard)
+
+
+Goals, resolving those issues
+------------------------------------
+
+This document discusses a possible solution for each of these issues,
+namely these goals:
+ 
+- allow to more easily define and run dependency/interpreter variants 
+  with testenvs
+- allow platform-specific settings
+- allow to specify platforms against which tests should run
+- allow to run installer-variants (easy_install or pip, xxx)
+- try to mimick/re-use bash-style syntax to ease learning curve.
+
+ 
+Example: Generating and selecting variants
+----------------------------------------------
+ 
+Suppose you want to test your package against python2.6, python2.7 and on the
+windows and linux platforms.  Today you would have to 
+write down 2*2 = 4 ``[testenv:*]`` sections and then instruct
+tox to run a specific list of environments on each platform.
+ 
+With tox-1.X you can directlys specify combinations::
+ 
+    # combination syntax gives 2 * 2 = 4 testenv names
+    #
+    envlist = {py26,py27}-{win,linux}
+     
+    [testenv]
+    deps = pytest
+    platform =
+           win: windows
+           linux: linux
+    basepython =
+           py26: python2.6
+           py27: python2.7
+    commands = py.test
+
+Let's go through this step by step::
+
+    envlist = {py26,py27}-{windows,linux}
+
+This is bash-style syntax and will create ``2*2=4`` environment names
+like this::
+
+    py26-windows
+    py26-linux
+    py27-windows
+    py27-linux
+
+Our ``[testenv]`` uses a new templating style for the ``platform`` definition::
+
+    platform=
+           windows: windows
+           linux: linux
+
+These two conditional settings will lead to either ``windows`` or
+``linux`` as the platform string.  When the test environment is run,
+its platform string needs to be contained in the string returned 
+from ``platform.platform()``. Otherwise the environment will be skipped.
+
+The next configuration item in the ``testenv`` section deals with
+the python interpreter::
+
+    basepython =
+           py26: python2.6
+           py27: python2.7
+
+This defines a python executable, depending on if ``py26`` or ``py27``
+appears in the environment name.
+
+The last config item is simply the invocation of the test runner::
+
+    commands = py.test
+
+Nothing special here :)
+
+.. note::
+
+    Tox provides good defaults for platform and basepython
+    settings, so the above ini-file can be further reduced::
+
+        [tox]
+        envlist = {py26,py27}-{win,linux}
+         
+        [testenv]
+        deps = pytest
+        commands = py.test
+
+    Voila, this multi-dimensional ``tox.ini`` configuration 
+    defines 2*2=4 environments.
+
+ 
+The new "platform" setting
+--------------------------------------
+
+A testenv can define a new ``platform`` setting.  If its value
+is not contained in the string obtained from calling 
+``platform.platform()`` the environment will be skipped.
+
+Expanding the ``envlist`` setting
+----------------------------------------------------------
+ 
+The new ``envlist`` setting allows to use ``{}`` bash-style
+expressions.  XXX explanation or pointer to bash-docs
+
+Templating based on environments names
+-------------------------------------------------
+
+For a given environment name, all lines in a testenv section which
+start with "NAME: ..." will be checked for being part in the environment
+name.  If they are part of it, the remainder will be the new line.
+If they are not part of it, the whole line will be left out.
+Parts of an environment name are obtained by ``-``-splitting it.
+                                                                                
+Variant specification with [variant:VARNAME]
+
+Showing all expanded sections
+-------------------------------
+
+To help with understanding how the variants will produce section values,
+you can ask tox to show their expansion with a new option::
+
+    $ tox -l [XXX output ommitted for now]
+
+Making sure your packages installs with easy_install
+------------------------------------------------------
+ 
+The new "installer" testenv setting allows to specify the tool for
+installation in a given test environment::
+ 
+    [testenv]
+    installer = 
+        easy: easy_install
+        pip: pip
+
+If you want to have your package installed with both easy_install
+and pip, you can list them in your envlist likes this::
+
+    [tox]
+    envlist = py[26,27,32]-django[13,14]-[easy,pip]
+
+If no installer is specified, ``pip`` will be used.
+
+Default settings related to environments names/variants
+---------------------------------------------------------------
+
+tox comes with predefined settings for certain variants, namely:
+
+* ``{easy,pip}`` use easy_install or pip respectively
+* ``{py24,py25,py26,py27,py31,py32,py33,pypy19]`` use the respective
+  pythonNN or PyPy interpreter
+* ``{win32,linux,darwin}`` defines the according ``platform``.
+
+You can use those in your “envlist” specification 
+without the need to define them yourself.
+
+
+Use more bash-style syntax
+--------------------------------------
+
+tox leverages bash-style syntax if you specify mintoxversion = 1.4:
+
+- $VARNAME or ${...} syntax instead of the older {} substitution.
+- XXX go through config.txt and see how it would need to be changed
+
+ 
+Transforming the examples: django-rest
+------------------------------------------------
+
+The original `django-rest-framework tox.ini
+<http://code.larlet.fr/django-rest-framework/src/eed0f39a7e45/tox.ini>`_
+file has 159 lines and a lot of repetition, the new one would +have 20
+lines and almost no repetition::
+ 
+     [tox]
+     envlist = {py25,py26,py27}-{django12,django13}{,-example}
+ 
+     [testenv]
+     deps=
+         coverage==3.4
+         unittest-xml-reporting==1.2
+         Pyyaml==3.10
+         django12: django==1.2.4
+         django13: django==1.3.1
+         # some more deps for running examples
+         example: wsgiref==0.1.2
+         example: Pygments==1.4
+         example: httplib2==0.6.0
+         example: Markdown==2.0.3
+
+     commands = 
+        !example: python setup.py test
+        example: python examples/runtests.py
+
+ 
+Note that ``{,-example}`` in the envlist denotes two values, an empty
+one and a ``example`` one.  The empty value means that there are no specific
+settings and thus no need to define a variant name. 
+
+Transforming the examples: django-treebeard
+------------------------------------------------
+ 
+Another `tox.ini
+<https://bitbucket.org/tabo/django-treebeard/raw/93b579395a9c/tox.ini>`_
+has 233 lines and runs tests against multiple Postgres and Mysql
+engines.  It also performs backend-specific test commands, passing
+different command line options to the test script.  With the new tox-1.X
+we not only can do the same with 32 non-repetive configuration lines but
+we also produce 36 specific testenvs with specific dependencies and test
+commands::
+ 
+    [tox]
+    envlist =
+     {py24,py25,py26,py27}-{django11,django12,django13}-{nodb,pg,mysql}, docs
+
+    [testenv:docs]
+    changedir = docs
+    deps =
+        Sphinx
+        Django
+    commands =
+        make clean
+        make html
+
+     [testenv]
+     deps=
+           coverage
+           pysqlite
+           django11: django==1.1.4
+           django12: django==1.2.7
+           django13: django==1.3.1
+           django14: django==1.4
+           nodb: pysqlite
+           pg: psycopg2
+           mysql: MySQL-python
+ 
+     commands = 
+         nodb: {envpython} runtests.py {posargs}
+         pg: {envpython} runtests.py {posargs} \
+                         --DATABASE_ENGINE=postgresql_psycopg2 \
+                         --DATABASE_USER=postgres {posargs}
+         mysql: {envpython} runtests.py --DATABASE_ENGINE=mysql \
+                                        --DATABASE_USER=root {posargs}
+
diff --git a/doc/config.txt b/doc/config.txt
index 02511de..0964146 100644
--- a/doc/config.txt
+++ b/doc/config.txt
@@ -35,7 +35,7 @@ and will first lookup global tox settings in this section::
 envlist setting
 +++++++++++++++++++++++++
 
-Determining the environment list that ``tox`` is to operate one
+Determining the environment list that ``tox`` is to operate on
 happens in this order:
 
 * command line option ``-eENVLIST``
@@ -75,6 +75,16 @@ Complete list of settings that you can put into ``testenv*`` sections:
     For eventually performing a call to ``subprocess.Popen(args, ...)``
     ``args`` are determined by splitting the whole command by whitespace.
 
+.. confval:: whitelist_externals=MULTI-LINE-LIST
+
+    each line specifies a command name (in glob-style pattern format)
+    which can be used in the ``commands`` section without triggering
+    a "not installed in virtualenv" warning.  Example: if you use the 
+    unix ``make`` for running tests you can list ``whitelist_externals=make``
+    or ``whitelist_externals=/usr/bin/make`` if you want more precision.
+    If you don't want tox to issue a warning in any case, just use
+    ``whitelist_externals=*`` which will match all commands (not recommended).
+
 .. confval:: changedir=path
 
     change to this working directory when executing the test command.
@@ -106,17 +116,21 @@ Complete list of settings that you can put into ``testenv*`` sections:
 
 .. confval:: downloadcache=path
 
-    (pip only) use this directory for caching downloads - this defaults to the
-    environment variable ``PIP_DOWNLOAD_CACHE`` if it is set.
+    (pip only) use this directory for caching downloads.  This value
+    is overriden by the environment variable ``PIP_DOWNLOAD_CACHE``
+    if it exists.
     **default**: no download cache will be used.
     **note**: if creating multiple environments use of a download cache greatly
     speeds up the testing process.
 
 .. confval:: distribute=True|False
 
-    Set to ``False`` if you want to use setuptools_ instead of the default
-    distribute_ in the virtual environment.
-    **default:** True.
+    Set to ``True`` if you want to use distribute_ instead of the default
+    setuptools_ in the virtual environment.  Prior to tox-1.5 the
+    default was True and now is False, meaning ``setuptools`` is used 
+    (note that setuptools-0.7 merged with distribute).  In future versions 
+    of tox this option might be ignored and setuptools always chosen.
+    **default:** False.
 
 .. confval:: sitepackages=True|False
 
@@ -199,6 +213,9 @@ substitutions for virtualenv-related sections
     directory of the virtualenv hierarchy
 ``{envbindir}``
     directory where executables are located
+``{envsitepackagesdir}``
+    directory where packages are installed.
+    Note that architecture-specific files may appear in a different directory.
 ``{envtmpdir}``
     the environment temporary directory
 ``{envlogdir}``
diff --git a/doc/example/basic.txt b/doc/example/basic.txt
index 3276ab1..031c4f9 100644
--- a/doc/example/basic.txt
+++ b/doc/example/basic.txt
@@ -37,12 +37,29 @@ Available "default" test environments names are::
     py30
     py31
     py32
+    py33
     jython
     pypy
 
 However, you can also create your own test environment names,
 see some of the examples in :doc:`examples <../examples>`.
 
+whitelisting a non-virtualenv commands
+-----------------------------------------------
+
+.. versionadded:: 1.5
+
+Sometimes you may want to use tools not contained in your
+virtualenv such as ``make``, ``bash`` or others. To avoid
+warnings you can use the ``whitelist_externals`` testenv
+configuration::
+
+    # content of tox.ini
+    [testenv]
+    whitelist_externals = make
+                          /bin/bash
+
+
 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
 
 .. _multiindex:
diff --git a/doc/example/jenkins.txt b/doc/example/jenkins.txt
index 2ec67ec..262aa15 100644
--- a/doc/example/jenkins.txt
+++ b/doc/example/jenkins.txt
@@ -34,9 +34,7 @@ for example with ``py.test`` it is done like this:
 
     commands=py.test --junitxml=junit-{envname}.xml
 
-See a real-life example in action with the `pytest Jenkins job`_
 
-.. _`pytest Jenkins job`: http://hudson.testrun.org/view/pytest/job/pytest/
 
 **zero-installation** for slaves
 -------------------------------------------------------------
diff --git a/doc/example/pytest.txt b/doc/example/pytest.txt
old mode 100755
new mode 100644
index 59e5147..98fa077
--- a/doc/example/pytest.txt
+++ b/doc/example/pytest.txt
@@ -85,16 +85,30 @@ created files in your py.test run.  Try to not use the "--basetemp" parameter.
 
 **installed-versus-checkout version**.  ``py.test`` collects test
 modules on the filesystem and then tries to import them under their
-`fully qualified name`_. This means that if your test directory contains
-an ``__init__.py`` file then your ``py.test`` invocation may end up
+`fully qualified name`_. This means that if your test files are
+importable from somewhere then your ``py.test`` invocation may end up
 importing the package from the checkout directory rather than the
-installed package.  Therefore it is better to try to avoid
-``__init__.py`` files in test directories and also try to avoid custom
-``PYTHONPATH`` settings.  After all, it is the job of your ``setup.py``
-file and the install tools to care for making the package properly
-available for importing.
+installed package.
+
+There are a few ways to prevent this.
+
+With installed tests (the tests packages are known to ``setup.py``), a
+safe and explicit option is to give the explicit path
+``{envsitepackagesdir}/mypkg`` to pytest.
+Alternatively, it is possible to use ``changedir`` so that checked-out
+files are outside the import path, then pass ``--pyargs mypkg`` to
+pytest.
+
+Installed tests are particularly convenient when combined with
+`Distribute's 2to3 support` (``use_2to3``).
+
+With tests that won't be installed, the simplest way is to avoid
+``__init__.py`` files in test directories; pytest will still find them
+but they won't be copied to other places or be found by Python's import
+system.
 
 .. _`fully qualified name`: http://pytest.org/latest/goodpractises.html#package-name
 
+.. _`Distribute's 2to3 support`: http://packages.python.org/distribute/python3.html
 
 .. include:: ../links.txt
diff --git a/doc/index.txt b/doc/index.txt
index f8ecf34..20d65d4 100644
--- a/doc/index.txt
+++ b/doc/index.txt
@@ -1,12 +1,14 @@
 Welcome to the tox automation project
 ===============================================
 
-vision: merge packaging, testing and release
+.. note:: Upcoming: `professional testing with pytest and tox <http://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_ , 24th-26th June 2013, Leipzig.
+
+vision: standardize testing in Python
 ---------------------------------------------
 
-``tox`` aims to automate state-of-the-art packaging, testing and
-releasing of Python software right from your console *or* CI
-server, invoking your tools of choice.
+``tox`` aims to automate and standardize testing in Python.  It is part
+of a larger vision of easing the packaging, testing and release process 
+of Python software.
 
 What is Tox?
 --------------------
@@ -36,6 +38,9 @@ right next to your ``setup.py`` file::
     deps=pytest       # install pytest in the venvs
     commands=py.test  # or 'nosetests' or ...
 
+You can also try generating a ``tox.ini`` file automatically, by running
+``tox-quickstart`` and then answering a few simple questions.
+
 To sdist-package, install and test your project against Python2.6 and Python2.7, just type::
 
     tox
@@ -61,10 +66,10 @@ Current features
 
 * supports :ref:`using different / multiple PyPI index servers  <multiindex>`
 
-* uses pip_ (for Python2 environments) and distribute_ (for all environments) by default
+* uses pip_ and distribute_ by default.
 
-* **cross-Python compatible**: Python-2.5 up to Python-3.2, Jython and 
-  Python3 support as well as for pypy_
+* **cross-Python compatible**: Python-2.5 up to Python-3.3, Jython and pypy_
+  support.
 
 * **cross-platform**: Windows and Unix style environments
 
@@ -93,7 +98,7 @@ Current features
    install
    examples
    config
-   config-v1
+   config-v2
    support
    changelog
    links
@@ -103,6 +108,7 @@ Current features
    announce/release-1.2
    announce/release-1.3
    announce/release-1.4
+   announce/release-1.4.3
 
 
 .. include:: links.txt
diff --git a/doc/install.txt b/doc/install.txt
index 6394920..c794692 100644
--- a/doc/install.txt
+++ b/doc/install.txt
@@ -4,13 +4,13 @@ tox installation
 Install info in a nutshell
 ----------------------------------
 
-**Pythons**: CPython 2.4-3.2, Jython-2.5.1, pypy-1.5
+**Pythons**: CPython 2.4-3.3, Jython-2.5.1, pypy-1.9ff
 
 **Operating systems**: Linux, Windows, OSX, Unix
 
 **Installer Requirements**: setuptools_ or Distribute_
 
-**License**: GPLv2 or later
+**License**: MIT license
 
 **hg repository**: http://bitbucket.org/hpk42/tox
 
diff --git a/doc/links.txt b/doc/links.txt
index 6362816..96f85c3 100644
--- a/doc/links.txt
+++ b/doc/links.txt
@@ -1,20 +1,20 @@
 
 .. _Python: http://www.python.org
-.. _virtualenv: http://pypi.python.org/pypi/virtualenv
-.. _virtualenv3: http://pypi.python.org/pypi/virtualenv3
-.. _virtualenv5: http://pypi.python.org/pypi/virtualenv5
+.. _virtualenv: https://pypi.python.org/pypi/virtualenv
+.. _virtualenv3: https://pypi.python.org/pypi/virtualenv3
+.. _virtualenv5: https://pypi.python.org/pypi/virtualenv5
 .. _`py.test`: http://pytest.org
 .. _nosetests:
-.. _`nose`: http://pypi.python.org/pypi/nose
-.. _`Holger Krekel`: http://twitter.com/hpk42
-.. _`pytest-xdist`: http://pypi.python.org/pypi/pytest-xdist
+.. _`nose`: https://pypi.python.org/pypi/nose
+.. _`Holger Krekel`: https://twitter.com/hpk42
+.. _`pytest-xdist`: https://pypi.python.org/pypi/pytest-xdist
 
 .. _`easy_install`: http://peak.telecommunity.com/DevCenter/EasyInstall
-.. _pip: http://pypi.python.org/pypi/pip
-.. _setuptools: http://pypi.python.org/pypi/setuptools
-.. _distribute: http://pypi.python.org/pypi/distribute
+.. _pip: https://pypi.python.org/pypi/pip
+.. _setuptools: https://pypi.python.org/pypi/setuptools
+.. _distribute: https://pypi.python.org/pypi/distribute
 .. _`jenkins`: http://jenkins-ci.org/
-.. _sphinx: http://pypi.python.org/pypi/Sphinx
-.. _discover: http://pypi.python.org/pypi/discover
-.. _unittest2: http://pypi.python.org/pypi/unittest2
-.. _mock: http://pypi.python.org/pypi/mock/
+.. _sphinx: https://pypi.python.org/pypi/Sphinx
+.. _discover: https://pypi.python.org/pypi/discover
+.. _unittest2: https://pypi.python.org/pypi/unittest2
+.. _mock: https://pypi.python.org/pypi/mock/
diff --git a/doc/support.txt b/doc/support.txt
index 30b7b36..1ece16a 100644
--- a/doc/support.txt
+++ b/doc/support.txt
@@ -4,24 +4,24 @@
 support and contact channels
 =====================================
 
-You are welcome to:
+Getting in contact:
 
 * join the `Testing In Python (TIP) mailing list`_ for general and tox/test-tool
   interaction questions.
 * file a `report on the issue tracker`_
-* join `tox-commit`_ to be notified of source changes
 * hang out on the irc.freenode.net #pylib channel
 * `clone the mercurial repository`_ and submit patches
-* follow the `tetamap blog`_ or `holger's twitter presence`_ or 
-  if all else fails contact holger krekel at gmail.
+* the `tetamap blog`_, `holger's twitter presence`_ or 
+  for private inquiries holger krekel at gmail.
 
 professional support
 ----------------------------
 
-If you are looking for on-site teaching and consulting report to setup
-and use state-of-the-start testing infrastructure with Python,
+.. note:: Upcoming: `professional testing with pytest and tox <`http://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_ , 24th-26th June 2013, Leipzig.
+
+If you are looking for on-site teaching or consulting support,
 contact holger at `merlinux.eu`_, an association of
-experienced and `well-known Python developers`_.
+experienced `well-known Python developers`_.
 
 .. _`well-known Python developers`: http://merlinux.eu/people.txt
 .. _`Maciej Fijalkowski`: http://www.ohloh.net/accounts/fijal
@@ -30,7 +30,7 @@ experienced and `well-known Python developers`_.
 .. _`holger's twitter presence`: http://twitter.com/hpk42
 .. _`merlinux.eu`: http://merlinux.eu
 .. _`report on the issue tracker`: https://bitbucket.org/hpk42/tox/issues?status=new&status=open
-.. _`tetamap blog`: http://tetamap.wordpress.com
+.. _`tetamap blog`: http://holgerkrekel.net
 .. _`tox-dev`: http://codespeak.net/mailman/listinfo/tox-dev
 .. _`tox-commit`: http://codespeak.net/mailman/listinfo/tox-commit
 .. _`clone the mercurial repository`: https://bitbucket.org/hpk42/tox
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..861a9f5
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/setup.py b/setup.py
index 75acf3b..095275f 100644
--- a/setup.py
+++ b/setup.py
@@ -2,57 +2,37 @@ import sys
 from setuptools import setup
 from setuptools.command.test import test as TestCommand
 
-long_description="""
-What is Tox?
-==========================
 
-Tox as is a generic virtualenv management and test command line tool you can
-use for:
-
-* checking your package installs correctly with different
-  Python versions and interpreters
-
-* running your tests in each of the
-  environments, configuring your test tool of choice
-
-* acting as a frontend to Continuous Integration
-  servers, greatly reducing boilerplate and merging
-  CI and shell-based testing.
-
-For more information, docs and many examples please checkout the `home page`_:
-
-    http://tox.testrun.org/
-
-.. _`home page`: http://tox.testrun.org/
-"""
 
 class Tox(TestCommand):
     def finalize_options(self):
         TestCommand.finalize_options(self)
-        self.test_args = []
+        self.test_args = ["-v", "-epy"]
         self.test_suite = True
+
     def run_tests(self):
         #import here, cause outside the eggs aren't loaded
         import tox
         tox.cmdline(self.test_args)
 
+
 def main():
     version = sys.version_info[:2]
-    install_requires = ['virtualenv>=1.7', 'py>=1.4.9', ]
-    if version < (2,7) or (3,0) <= version <= (3,1):
+    install_requires = ['virtualenv>=1.9.1', 'py>=1.4.15', ]
+    if version < (2, 7) or (3, 0) <= version <= (3, 1):
         install_requires += ['argparse']
     setup(
         name='tox',
         description='virtualenv-based automation of test activities',
-        long_description=long_description,
-        url='http://codespeak.net/tox',
-        version='1.4.2',
-        license='GPLv2 or later',
+        long_description=open("README.rst").read(),
+        url='http://tox.testrun.org/',
+        version='1.5.0',
+        license='http://opensource.org/licenses/MIT',
         platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
         author='holger krekel',
         author_email='holger at merlinux.eu',
         packages=['tox', ],
-        entry_points={'console_scripts': 'tox=tox:cmdline'},
+        entry_points={'console_scripts': 'tox=tox:cmdline\ntox-quickstart=tox._quickstart:main'},
         # we use a public tox version to test, see tox.ini's testenv
         # "deps" definition for the required dependencies
         tests_require=['tox'],
@@ -62,15 +42,15 @@ def main():
         classifiers=[
             'Development Status :: 5 - Production/Stable',
             'Intended Audience :: Developers',
-            'License :: OSI Approved :: GNU General Public License (GPL)',
-             'Operating System :: POSIX',
-             'Operating System :: Microsoft :: Windows',
-             'Operating System :: MacOS :: MacOS X',
-             'Topic :: Software Development :: Testing',
-             'Topic :: Software Development :: Libraries',
-             'Topic :: Utilities',
-             'Programming Language :: Python',
-             'Programming Language :: Python :: 3'],
+            'License :: OSI Approved :: MIT License',
+            'Operating System :: POSIX',
+            'Operating System :: Microsoft :: Windows',
+            'Operating System :: MacOS :: MacOS X',
+            'Topic :: Software Development :: Testing',
+            'Topic :: Software Development :: Libraries',
+            'Topic :: Utilities',
+            'Programming Language :: Python',
+            'Programming Language :: Python :: 3'],
     )
 
 if __name__ == '__main__':
diff --git a/tests/conftest.py b/tests/conftest.py
index 51bc0a2..1d4bdde 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,289 +1,2 @@
-import py
-import tox
-import os
-import sys
-from py.builtin import print_
-from fnmatch import fnmatch
-import time
-from tox._config import parseconfig
-from tox._venv import VirtualEnv
-from tox._cmdline import Action
 
-def pytest_configure():
-    if 'TOXENV' in os.environ:
-        del os.environ['TOXENV']
-    if 'HUDSON_URL' in os.environ:
-        del os.environ['HUDSON_URL']
-
-def pytest_report_header():
-    return "tox comes from: %r" % (tox.__file__)
-
-def pytest_funcarg__newconfig(request):
-    tmpdir = request.getfuncargvalue("tmpdir")
-    def newconfig(args, source=None):
-        if source is None:
-            source = args
-            args = []
-        s = py.std.textwrap.dedent(source)
-        p = tmpdir.join("tox.ini")
-        p.write(s)
-        old = tmpdir.chdir()
-        try:
-            return parseconfig(args)
-        finally:
-            old.chdir()
-    return newconfig
-
-def pytest_funcarg__tmpdir(request):
-    tmpdir = request.getfuncargvalue("tmpdir")
-    request.addfinalizer(py.path.local().chdir)
-    tmpdir.chdir()
-    return tmpdir
-
-def pytest_funcarg__cmd(request):
-    return Cmd(request)
-
-class ReportExpectMock:
-    def __init__(self, session):
-        self._calls = []
-        self._index = -1
-        self.session = session
-
-    def clear(self):
-        self._calls[:] = []
-
-    def __getattr__(self, name):
-        if name[0] == "_":
-            raise AttributeError(name)
-
-        def generic_report(*args, **kwargs):
-            self._calls.append((name,)+args)
-            print ("%s" %(self._calls[-1], ))
-        return generic_report
-
-    def action(self, venv, msg, *args):
-        self._calls.append(("action", venv, msg))
-        print ("%s" %(self._calls[-1], ))
-        return Action(self.session, venv, msg, args)
-
-    def getnext(self, cat):
-        __tracebackhide__ = True
-        newindex = self._index + 1
-        while newindex < len(self._calls):
-            call = self._calls[newindex]
-            lcat = call[0]
-            if fnmatch(lcat, cat):
-                self._index = newindex
-                return call
-            newindex += 1
-        raise LookupError(
-            "looking for %r, no reports found at >=%d in %r" %
-            (cat, self._index+1, self._calls))
-
-    def expect(self, cat, messagepattern="*", invert=False):
-        __tracebackhide__ = True
-        if not messagepattern.startswith("*"):
-            messagepattern = "*" + messagepattern
-        while self._index < len(self._calls):
-            try:
-                call = self.getnext(cat)
-            except LookupError:
-                break
-            for lmsg in call[1:]:
-                lmsg = str(lmsg).replace("\n", " ")
-                if fnmatch(lmsg, messagepattern):
-                    if invert:
-                        raise AssertionError("found %s(%r), didn't expect it" %
-                            (cat, messagepattern))
-                    return
-        if not invert:
-            raise AssertionError(
-             "looking for %s(%r), no reports found at >=%d in %r" %
-                (cat, messagepattern, self._index+1, self._calls))
-
-    def not_expect(self, cat, messagepattern="*"):
-        return self.expect(cat, messagepattern, invert=True)
-
-class pcallMock:
-    def __init__(self, args, cwd, env, stdout, stderr, shell):
-        self.args = args
-        self.cwd = cwd
-        self.env = env
-        self.stdout = stdout
-        self.stderr = stderr
-        self.shell = shell
-
-    def communicate(self):
-        return "", ""
-    def wait(self):
-        pass
-
-def pytest_funcarg__mocksession(request):
-    from tox._cmdline import Session
-    class MockSession(Session):
-        def __init__(self):
-            self._clearmocks()
-            self.config = request.getfuncargvalue("newconfig")([], "")
-            self._actions = []
-        def getenv(self, name):
-            return VirtualEnv(self.config.envconfigs[name], session=self)
-        def _clearmocks(self):
-            self._pcalls = []
-            self._spec2pkg = {}
-            self.report = ReportExpectMock(self)
-        def make_emptydir(self, path):
-            pass
-        def popen(self, args, cwd, shell=None,
-            stdout=None, stderr=None, env=None):
-            pm = pcallMock(args, cwd, env, stdout, stderr, shell)
-            self._pcalls.append(pm)
-            return pm
-    return MockSession()
-
-def pytest_funcarg__newmocksession(request):
-    mocksession = request.getfuncargvalue("mocksession")
-    newconfig = request.getfuncargvalue("newconfig")
-    def newmocksession(args, source):
-        config = newconfig(args, source)
-        mocksession.config = config
-        return mocksession
-    return newmocksession
-
-class Cmd:
-    def __init__(self, request):
-        self.tmpdir = request.getfuncargvalue("tmpdir")
-        self.request = request
-        current = py.path.local()
-        self.request.addfinalizer(current.chdir)
-    def chdir(self, target):
-        target.chdir()
-
-    def popen(self, argv, stdout, stderr, **kw):
-        if not hasattr(py.std, 'subprocess'):
-            py.test.skip("no subprocess module")
-        env = os.environ.copy()
-        env['PYTHONPATH'] = ":".join(filter(None, [
-            str(os.getcwd()), env.get('PYTHONPATH', '')]))
-        kw['env'] = env
-        #print "env", env
-        return py.std.subprocess.Popen(argv, stdout=stdout, stderr=stderr, **kw)
-
-    def run(self, *argv):
-        argv = [str(x) for x in argv]
-        p1 = self.tmpdir.join("stdout")
-        p2 = self.tmpdir.join("stderr")
-        print("%s$ %s" % (os.getcwd(), " ".join(argv)))
-        f1 = p1.open("wb")
-        f2 = p2.open("wb")
-        now = time.time()
-        popen = self.popen(argv, stdout=f1, stderr=f2,
-            close_fds=(sys.platform != "win32"))
-        ret = popen.wait()
-        f1.close()
-        f2.close()
-        out = p1.read("rb")
-        out = getdecoded(out).splitlines()
-        err = p2.read("rb")
-        err = getdecoded(err).splitlines()
-        def dump_lines(lines, fp):
-            try:
-                for line in lines:
-                    py.builtin.print_(line, file=fp)
-            except UnicodeEncodeError:
-                print("couldn't print to %s because of encoding" % (fp,))
-        dump_lines(out, sys.stdout)
-        dump_lines(err, sys.stderr)
-        return RunResult(ret, out, err, time.time()-now)
-
-def getdecoded(out):
-        try:
-            return out.decode("utf-8")
-        except UnicodeDecodeError:
-            return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % (
-                    py.io.saferepr(out),)
-
-class RunResult:
-    def __init__(self, ret, outlines, errlines, duration):
-        self.ret = ret
-        self.outlines = outlines
-        self.errlines = errlines
-        self.stdout = LineMatcher(outlines)
-        self.stderr = LineMatcher(errlines)
-        self.duration = duration
-
-class LineMatcher:
-    def __init__(self,  lines):
-        self.lines = lines
-
-    def str(self):
-        return "\n".join(self.lines)
-
-    def fnmatch_lines(self, lines2):
-        if isinstance(lines2, str):
-            lines2 = py.code.Source(lines2)
-        if isinstance(lines2, py.code.Source):
-            lines2 = lines2.strip().lines
-
-        from fnmatch import fnmatch
-        lines1 = self.lines[:]
-        nextline = None
-        extralines = []
-        __tracebackhide__ = True
-        for line in lines2:
-            nomatchprinted = False
-            while lines1:
-                nextline = lines1.pop(0)
-                if line == nextline:
-                    print_("exact match:", repr(line))
-                    break
-                elif fnmatch(nextline, line):
-                    print_("fnmatch:", repr(line))
-                    print_("   with:", repr(nextline))
-                    break
-                else:
-                    if not nomatchprinted:
-                        print_("nomatch:", repr(line))
-                        nomatchprinted = True
-                    print_("    and:", repr(nextline))
-                extralines.append(nextline)
-            else:
-                assert line == nextline
-
-def pytest_funcarg__initproj(request):
-    """ create a factory function for creating example projects. """
-    tmpdir = request.getfuncargvalue("tmpdir")
-    def initproj(name, filedefs=None):
-        if filedefs is None:
-            filedefs = {}
-        parts = name.split("-")
-        if len(parts) == 1:
-            parts.append("0.1")
-        name, version = parts
-        base = tmpdir.ensure(name, dir=1)
-        create_files(base, filedefs)
-        if 'setup.py' not in filedefs:
-            create_files(base, {'setup.py': '''
-                from setuptools import setup
-                setup(
-                    name='%(name)s',
-                    description='%(name)s project',
-                    version='%(version)s',
-                    license='GPLv2 or later',
-                    platforms=['unix', 'win32'],
-                    packages=['%(name)s', ],
-                )
-            ''' % locals()})
-        if name not in filedefs:
-            create_files(base, {name:
-                {'__init__.py': '__version__ = %s' % version}})
-        print ("created project in %s" %(base,))
-        base.chdir()
-    return initproj
-
-def create_files(base, filedefs):
-    for key, value in filedefs.items():
-        if isinstance(value, dict):
-            create_files(base.ensure(key, dir=1), value)
-        elif isinstance(value, str):
-            s = py.std.textwrap.dedent(value)
-            base.join(key).write(s)
+from tox._pytestplugin import *
diff --git a/tests/test_config.py b/tests/test_config.py
index 9ad8398..037fc26 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -1,9 +1,12 @@
 import tox
+import pytest
 import os, sys
+import subprocess
 from textwrap import dedent
 
 import py
 from tox._config import IniReader, CommandParser
+from tox._config import parseconfig
 
 class TestVenvConfig:
     def test_config_parsing_minimal(self, tmpdir, newconfig):
@@ -22,10 +25,8 @@ class TestVenvConfig:
             indexserver =
                 xyz = xyz_repo
             [testenv:py1]
-            basepython=xyz
             deps=hello
             [testenv:py2]
-            basepython=hello
             deps=
                 world1
                 :xyz:http://hello/world
@@ -33,11 +34,9 @@ class TestVenvConfig:
         assert config.toxworkdir == tmpdir
         assert len(config.envconfigs) == 2
         assert config.envconfigs['py1'].envdir == tmpdir.join("py1")
-        assert config.envconfigs['py1'].basepython == "xyz"
         dep = config.envconfigs['py1'].deps[0]
         assert dep.name == "hello"
         assert dep.indexserver is None
-        assert config.envconfigs['py2'].basepython == "hello"
         assert config.envconfigs['py2'].envdir == tmpdir.join("py2")
         dep1, dep2 = config.envconfigs['py2'].deps
         assert dep1.name == "world1"
@@ -73,6 +72,17 @@ class TestConfigPackage:
         """ % tmpdir)
         assert config.toxworkdir == tmpdir
 
+class TestParseconfig:
+    def test_search_parents(self, tmpdir):
+        b = tmpdir.mkdir("a").mkdir("b")
+        toxinipath = tmpdir.ensure("tox.ini")
+        old = b.chdir()
+        try:
+            config = parseconfig([])
+        finally:
+            old.chdir()
+        assert config.toxinipath == toxinipath
+
 class TestIniParser:
     def test_getdefault_single(self, tmpdir, newconfig):
         config = newconfig("""
@@ -166,6 +176,29 @@ class TestIniParser:
         py.test.raises(tox.exception.ConfigError,
             'reader.getdefault("section", "key2")')
 
+    def test_getdefault_other_section_substitution(self, newconfig):
+        config = newconfig("""
+            [section]
+            key = rue
+            [testenv]
+            key = t{[section]key}
+            """)
+        reader = IniReader(config._cfg)
+        x = reader.getdefault("testenv", "key")
+        assert x == "true"
+
+    def test_command_substitution_from_other_section(self, newconfig):
+        config = newconfig("""
+            [section]
+            key = whatever
+            [testenv]
+            commands =
+                echo {[section]key}
+            """)
+        reader = IniReader(config._cfg)
+        x = reader.getargvlist("testenv", "commands")
+        assert x == [["echo", "whatever"]]
+
     def test_argvlist(self, tmpdir, newconfig):
         config = newconfig("""
             [section]
@@ -319,7 +352,7 @@ class TestConfigTestEnv:
         envconfig = config.envconfigs['python']
         assert envconfig.commands == [["xyz", "--abc"]]
         assert envconfig.changedir == config.setupdir
-        assert envconfig.distribute == True
+        assert envconfig.distribute == False
         assert envconfig.sitepackages == False
         assert envconfig.envlogdir == envconfig.envdir.join("log")
         assert envconfig.setenv is None
@@ -328,13 +361,31 @@ class TestConfigTestEnv:
         config = newconfig("""
             [testenv]
             commands=xyz
-            [testenv:py30]
+            [testenv:py]
             commands=abc
         """)
         assert len(config.envconfigs) == 1
-        envconfig = config.envconfigs['py30']
+        envconfig = config.envconfigs['py']
         assert envconfig.commands == [["abc"]]
 
+    def test_whitelist_externals(self, tmpdir, newconfig):
+        config = newconfig("""
+            [testenv]
+            whitelist_externals = xyz
+            commands=xyz
+            [testenv:x]
+
+            [testenv:py]
+            whitelist_externals = xyz2
+            commands=abc
+        """)
+        assert len(config.envconfigs) == 2
+        envconfig = config.envconfigs['py']
+        assert envconfig.commands == [["abc"]]
+        assert envconfig.whitelist_externals == ["xyz2"]
+        envconfig = config.envconfigs['x']
+        assert envconfig.whitelist_externals == ["xyz"]
+
     def test_changedir(self, tmpdir, newconfig):
         config = newconfig("""
             [testenv]
@@ -354,14 +405,18 @@ class TestConfigTestEnv:
         envconfig = config.envconfigs['python']
         assert envconfig.envpython == envconfig.envbindir.join("python")
 
-    def test_envbindir_jython(self, tmpdir, newconfig):
+    @pytest.mark.parametrize("bp", ["jython", "pypy"])
+    def test_envbindir_jython(self, tmpdir, newconfig, bp):
         config = newconfig("""
             [testenv]
-            basepython=jython
-        """)
+            basepython=%s
+        """ % bp)
         assert len(config.envconfigs) == 1
         envconfig = config.envconfigs['python']
-        assert envconfig.envpython == envconfig.envbindir.join("jython")
+        # on win32 and linux virtualenv uses "bin" for pypy/jython
+        assert envconfig.envbindir.basename == "bin"
+        if bp == "jython":
+            assert envconfig.envpython == envconfig.envbindir.join(bp)
 
     def test_setenv_overrides(self, tmpdir, newconfig):
         config = newconfig("""
@@ -429,7 +484,7 @@ class TestConfigTestEnv:
         assert argv[3][0] == conf.envbindir
         assert argv[4][0] == conf.envtmpdir
         assert argv[5][0] == conf.envpython
-        assert argv[6][0] == os.path.expanduser("~")
+        assert argv[6][0] == str(py.path.local._gethomedir())
         assert argv[7][0] == config.homedir.join(".tox", "distshare")
         assert argv[8][0] == conf.envlogdir
 
@@ -577,6 +632,35 @@ class TestConfigTestEnv:
         assert conf.changedir.basename == 'testing'
         assert conf.changedir.dirpath().realpath() == tmpdir.realpath()
 
+    @pytest.mark.xfailif("sys.platform == 'win32'")
+    def test_substitution_envsitepackagesdir(self, tmpdir, monkeypatch,
+                                             newconfig):
+        """
+         The envsitepackagesdir property is mostly doing system work,
+         so this test doesn't excercise it very well.
+
+         Usage of envsitepackagesdir on win32/jython will explicitly
+         throw an exception,
+        """
+        class MockPopen(object):
+            returncode = 0
+
+            def __init__(self, *args, **kwargs):
+                pass
+
+            def communicate(self, *args, **kwargs):
+                return 'onevalue', 'othervalue'
+
+        monkeypatch.setattr(subprocess, 'Popen', MockPopen)
+        env = 'py%s' % (''.join(sys.version.split('.')[0:2]))
+        config = newconfig("""
+            [testenv:%s]
+            commands = {envsitepackagesdir}
+        """ % (env))
+        conf = config.envconfigs[env]
+        argv = conf.commands
+        assert argv[0][0] == 'onevalue'
+
 
 class TestGlobalOptions:
     def test_notest(self, newconfig):
@@ -655,8 +739,13 @@ class TestGlobalOptions:
         config = newconfig(["-eALL"], inisource)
         assert config.envlist == ['py26', 'py27', 'py31']
 
+    def test_py_venv(self, tmpdir, newconfig, monkeypatch):
+        config = newconfig(["-epy"], "")
+        env = config.envconfigs['py']
+        assert str(env.basepython) == sys.executable
+
     def test_default_environments(self, tmpdir, newconfig, monkeypatch):
-        envs = "py24,py25,py26,py27,py30,py31,py32,jython,pypy"
+        envs = "py24,py25,py26,py27,py31,py32,jython,pypy"
         inisource = """
             [tox]
             envlist = %s
@@ -730,6 +819,26 @@ class TestIndexServer:
         assert config.indexserver['default'].url == "qwe2"
         assert config.indexserver['name1'].url == "abc"
 
+        config = newconfig(["-i", "ALL=xzy"], inisource)
+        assert len(config.indexserver) == 2
+        assert config.indexserver["default"].url == "xzy"
+        assert config.indexserver["name1"].url == "xzy"
+
+    def test_multiple_homedir_relative_local_indexservers(self, newconfig):
+        inisource = """
+            [tox]
+            indexserver =
+                default = file://{homedir}/.pip/downloads/simple
+                local1  = file://{homedir}/.pip/downloads/simple
+                local2  = file://{toxinidir}/downloads/simple
+                pypi    = http://pypi.python.org/simple
+        """
+        config = newconfig([], inisource)
+        homedir = str(py.path.local._gethomedir())
+        expected = "file://%s/.pip/downloads/simple" % homedir
+        assert config.indexserver['default'].url == expected
+        assert config.indexserver['local1'].url == \
+               config.indexserver['default'].url
 
 class TestParseEnv:
 
@@ -763,15 +872,28 @@ class TestCmdInvocation:
         assert tox.__version__ in stdout
         assert "imported from" in stdout
 
-    def test_unkonwn_ini(self, cmd):
-        result = cmd.run("tox")
-        assert result.ret
-        result.stderr.fnmatch_lines([
-            "*tox.ini*does not exist*",
-        ])
+    def test_listenvs(self, cmd, initproj):
+        initproj('listenvs', filedefs={
+            'tox.ini': '''
+            [tox]
+            envlist=py26,py27,py33,pypy,docs
+
+            [testenv:notincluded]
+            changedir = whatever
+
+            [testenv:docs]
+            changedir = docs
+            ''',
+        })
+        result = cmd.run("tox", "-l")
+        result.stdout.fnmatch_lines("""
+            *py26*
+            *py27*
+            *py33*
+            *pypy*
+            *docs*
+        """)
 
-    @py.test.mark.xfail("sys.version_info < (2,6)",
-        reason="virtualenv3 cannot be imported")
     def test_config_specific_ini(self, tmpdir, cmd):
         ini = tmpdir.ensure("hello.ini")
         result = cmd.run("tox", "-c", ini, "--showconfig")
@@ -785,10 +907,9 @@ class TestCmdInvocation:
         result = cmd.run("tox")
         assert result.ret
         result.stderr.fnmatch_lines([
-            "*ERROR*tox.ini*does not exist*",
+            "*ERROR*tox.ini*not*found*",
         ])
 
-
 class TestCommandParser:
 
     def test_command_parser_for_word(self):
diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py
new file mode 100644
index 0000000..64d8790
--- /dev/null
+++ b/tests/test_quickstart.py
@@ -0,0 +1,362 @@
+import pytest
+import tox._quickstart
+
+
+
+class TestToxQuickstartMain(object):
+    @pytest.fixture(autouse=True)
+    def cleandir(self, tmpdir):
+        tmpdir.chdir()
+
+    def mock_term_input_return_values(self, return_values):
+        for return_val in return_values:
+            yield return_val
+
+    def get_mock_term_input(self, return_values):
+        generator = self.mock_term_input_return_values(return_values)
+
+        def mock_term_input(prompt):
+            try:
+                return next(generator)
+            except NameError:
+                return generator.next()
+
+        return mock_term_input
+
+    def test_quickstart_main_choose_individual_pythons_and_pytest(self, monkeypatch):
+        monkeypatch.setattr(
+            tox._quickstart, 'term_input',
+            self.get_mock_term_input(['4', 'Y', 'Y', 'Y', 'Y', 'N', 'N', 'Y', 'Y', 'Y', 'N', 'py.test', 'pytest']))
+
+        tox._quickstart.main(argv=['tox-quickstart'])
+
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py24, py25, py26, py27, py32, py33, pypy
+
+[testenv]
+commands = py.test
+deps =
+    pytest
+""".lstrip()
+        result = open('tox.ini').read()
+        assert(result == expected_tox_ini)
+
+    def test_quickstart_main_choose_individual_pythons_and_nose_adds_deps(self, monkeypatch):
+        monkeypatch.setattr(
+            tox._quickstart, 'term_input',
+            self.get_mock_term_input(['4', 'Y', 'Y', 'Y', 'Y', 'N', 'N', 'Y', 'Y', 'Y', 'N', 'nosetests', '']))
+
+        tox._quickstart.main(argv=['tox-quickstart'])
+
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py24, py25, py26, py27, py32, py33, pypy
+
+[testenv]
+commands = nosetests
+deps =
+    nose
+""".lstrip()
+        result = open('tox.ini').read()
+        assert(result == expected_tox_ini)
+
+    def test_quickstart_main_choose_individual_pythons_and_trial_adds_deps(self, monkeypatch):
+        monkeypatch.setattr(
+            tox._quickstart, 'term_input',
+            self.get_mock_term_input(['4', 'Y', 'Y', 'Y', 'Y', 'N', 'N', 'Y', 'Y', 'Y', 'N', 'trial', '']))
+
+        tox._quickstart.main(argv=['tox-quickstart'])
+
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py24, py25, py26, py27, py32, py33, pypy
+
+[testenv]
+commands = trial
+deps =
+    twisted
+""".lstrip()
+        result = open('tox.ini').read()
+        assert(result == expected_tox_ini)
+
+    def test_quickstart_main_choose_individual_pythons_and_pytest_adds_deps(self, monkeypatch):
+        monkeypatch.setattr(
+            tox._quickstart, 'term_input',
+            self.get_mock_term_input(['4', 'Y', 'Y', 'Y', 'Y', 'N', 'N', 'Y', 'Y', 'Y', 'N', 'py.test', '']))
+
+        tox._quickstart.main(argv=['tox-quickstart'])
+
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py24, py25, py26, py27, py32, py33, pypy
+
+[testenv]
+commands = py.test
+deps =
+    pytest
+""".lstrip()
+        result = open('tox.ini').read()
+        assert(result == expected_tox_ini)
+
+    def test_quickstart_main_choose_py27_and_pytest_adds_deps(self, monkeypatch):
+        monkeypatch.setattr(
+            tox._quickstart, 'term_input',
+            self.get_mock_term_input(['1', 'py.test', '']))
+
+        tox._quickstart.main(argv=['tox-quickstart'])
+
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py27
+
+[testenv]
+commands = py.test
+deps =
+    pytest
+""".lstrip()
+        result = open('tox.ini').read()
+        assert(result == expected_tox_ini)
+
+    def test_quickstart_main_choose_py27_and_py33_and_pytest_adds_deps(self, monkeypatch):
+        monkeypatch.setattr(
+            tox._quickstart, 'term_input',
+            self.get_mock_term_input(['2', 'py.test', '']))
+
+        tox._quickstart.main(argv=['tox-quickstart'])
+
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py27, py33
+
+[testenv]
+commands = py.test
+deps =
+    pytest
+""".lstrip()
+        result = open('tox.ini').read()
+        assert(result == expected_tox_ini)
+
+    def test_quickstart_main_choose_all_pythons_and_pytest_adds_deps(self, monkeypatch):
+        monkeypatch.setattr(
+            tox._quickstart, 'term_input',
+            self.get_mock_term_input(['3', 'py.test', '']))
+
+        tox._quickstart.main(argv=['tox-quickstart'])
+
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py24, py25, py26, py27, py30, py31, py32, py33, pypy, jython
+
+[testenv]
+commands = py.test
+deps =
+    pytest
+""".lstrip()
+        result = open('tox.ini').read()
+        assert(result == expected_tox_ini)
+
+    def test_quickstart_main_choose_individual_pythons_and_defaults(self, monkeypatch):
+        monkeypatch.setattr(
+            tox._quickstart, 'term_input',
+            self.get_mock_term_input(['4', '', '', '', '', '', '', '', '', '', '', '', '']))
+
+        tox._quickstart.main(argv=['tox-quickstart'])
+
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py24, py25, py26, py27, py30, py31, py32, py33, pypy, jython
+
+[testenv]
+commands = {envpython} setup.py test
+deps =
+
+""".lstrip()
+        result = open('tox.ini').read()
+        assert(result == expected_tox_ini)
+
+    def test_quickstart_main_existing_tox_ini(self, monkeypatch):
+        try:
+            f = open('tox.ini', 'w')
+            f.write('foo bar\n')
+        finally:
+            f.close()
+
+        monkeypatch.setattr(
+            tox._quickstart, 'term_input',
+            self.get_mock_term_input(['4', '', '', '', '', '', '', '', '', '', '', '', '', '']))
+
+        tox._quickstart.main(argv=['tox-quickstart'])
+
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py24, py25, py26, py27, py30, py31, py32, py33, pypy, jython
+
+[testenv]
+commands = {envpython} setup.py test
+deps =
+
+""".lstrip()
+        result = open('tox-generated.ini').read()
+        assert(result == expected_tox_ini)
+
+
+class TestToxQuickstart(object):
+    def test_pytest(self):
+        d = {
+            'py24': True,
+            'py25': True,
+            'py26': True,
+            'py27': True,
+            'py32': True,
+            'py33': True,
+            'pypy': True,
+            'commands': 'py.test',
+            'deps': 'pytest',
+        }
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py24, py25, py26, py27, py32, py33, pypy
+
+[testenv]
+commands = py.test
+deps =
+    pytest
+""".lstrip()
+        d = tox._quickstart.process_input(d)
+        tox._quickstart.generate(d)
+        result = open('tox.ini').read()
+        # print(result)
+        assert(result == expected_tox_ini)
+
+    def test_setup_py_test(self):
+        d = {
+            'py26': True,
+            'py27': True,
+            'commands': 'python setup.py test',
+            'deps': '',
+        }
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py26, py27
+
+[testenv]
+commands = python setup.py test
+deps =
+
+""".lstrip()
+        d = tox._quickstart.process_input(d)
+        tox._quickstart.generate(d)
+        result = open('tox.ini').read()
+        # print(result)
+        assert(result == expected_tox_ini)
+
+    def test_trial(self):
+        d = {
+            'py27': True,
+            'commands': 'trial',
+            'deps': 'Twisted',
+        }
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py27
+
+[testenv]
+commands = trial
+deps =
+    Twisted
+""".lstrip()
+        d = tox._quickstart.process_input(d)
+        tox._quickstart.generate(d)
+        result = open('tox.ini').read()
+        # print(result)
+        assert(result == expected_tox_ini)
+
+    def test_nosetests(self):
+        d = {
+            'py27': True,
+            'py32': True,
+            'py33': True,
+            'pypy': True,
+            'commands': 'nosetests -v',
+            'deps': 'nose',
+        }
+        expected_tox_ini = """
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py27, py32, py33, pypy
+
+[testenv]
+commands = nosetests -v
+deps =
+    nose
+""".lstrip()
+        d = tox._quickstart.process_input(d)
+        tox._quickstart.generate(d)
+        result = open('tox.ini').read()
+        # print(result)
+        assert(result == expected_tox_ini)
diff --git a/tests/test_venv.py b/tests/test_venv.py
index 3db3a6b..e66aba9 100644
--- a/tests/test_venv.py
+++ b/tests/test_venv.py
@@ -3,6 +3,7 @@ import tox
 import pytest
 import os, sys
 from tox._venv import VirtualEnv, CreationConfig, getdigest
+from tox._venv import find_executable
 
 #def test_global_virtualenv(capfd):
 #    v = VirtualEnv()
@@ -15,8 +16,24 @@ from tox._venv import VirtualEnv, CreationConfig, getdigest
 def test_getdigest(tmpdir):
     assert getdigest(tmpdir) == "0"*32
 
+ at pytest.mark.skipif("sys.platform != 'win32'")
+def test_locate_via_py(monkeypatch):
+    from tox._venv import locate_via_py
+    class PseudoPy:
+        def sysexec(self, *args):
+            assert args[0] == '-3.2'
+            assert args[1] == '-c'
+            # Return value needs to actually exist!
+            return sys.executable
+    @staticmethod
+    def ret_pseudopy(name):
+        assert name == 'py'
+        return PseudoPy()
+    # Monkeypatch py.path.local.sysfind to return PseudoPy
+    monkeypatch.setattr(py.path.local, 'sysfind', ret_pseudopy)
+    assert locate_via_py('3', '2') == sys.executable
+
 def test_find_executable():
-    from tox._venv import find_executable
     p = find_executable(sys.executable)
     assert p == py.path.local(sys.executable)
     for ver in [""] + "2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3".split():
@@ -37,6 +54,14 @@ def test_find_executable():
         stdout, stderr = popen.communicate()
         assert ver in py.builtin._totext(stderr, "ascii")
 
+def test_find_executable_extra(monkeypatch):
+    @staticmethod
+    def sysfind(x):
+        return "hello"
+    monkeypatch.setattr(py.path.local, "sysfind", sysfind)
+    t = find_executable("qweqwe")
+    assert t == "hello"
+
 def test_getsupportedinterpreter(monkeypatch, newconfig, mocksession):
     config = newconfig([], """
         [testenv:python]
@@ -77,6 +102,20 @@ def test_create(monkeypatch, mocksession, newconfig):
     assert interp == venv.getconfigexecutable()
     assert venv.path_config.check(exists=False)
 
+ at pytest.mark.skipif("sys.platform == 'win32'")
+def test_commandpath_venv_precendence(tmpdir, monkeypatch,
+                                      mocksession, newconfig):
+    config = newconfig([], """
+        [testenv:py123]
+    """)
+    envconfig = config.envconfigs['py123']
+    venv = VirtualEnv(envconfig, session=mocksession)
+    tmpdir.ensure("easy_install")
+    monkeypatch.setenv("PATH", str(tmpdir), prepend=os.pathsep)
+    envconfig.envbindir.ensure("easy_install")
+    p = venv.getcommandpath("easy_install")
+    assert py.path.local(p).relto(envconfig.envbindir), p
+
 def test_create_distribute(monkeypatch, mocksession, newconfig):
     config = newconfig([], """
         [testenv:py123]
@@ -91,6 +130,7 @@ def test_create_distribute(monkeypatch, mocksession, newconfig):
     assert len(l) >= 1
     args = l[0].args
     assert "--distribute" not in map(str, args)
+    assert "--setuptools" in map(str, args)
 
 def test_create_sitepackages(monkeypatch, mocksession, newconfig):
     config = newconfig([], """
@@ -138,13 +178,18 @@ def test_install_deps_wildcard(newmocksession):
     assert l[1].cwd == venv.envconfig.envlogdir
     assert "pip" in str(args[0])
     assert args[1] == "install"
-    arg = "--download-cache=" + str(venv.envconfig.downloadcache)
-    assert arg in args[2:]
+    #arg = "--download-cache=" + str(venv.envconfig.downloadcache)
+    #assert arg in args[2:]
     args = [arg for arg in args if str(arg).endswith("dep1-1.1.zip")]
     assert len(args) == 1
 
 
-def test_install_downloadcache(newmocksession):
+ at pytest.mark.parametrize("envdc", [True, False])
+def test_install_downloadcache(newmocksession, monkeypatch, tmpdir, envdc):
+    if envdc:
+        monkeypatch.setenv("PIP_DOWNLOAD_CACHE", tmpdir)
+    else:
+        monkeypatch.delenv("PIP_DOWNLOAD_CACHE", raising=False)
     mocksession = newmocksession([], """
         [testenv:py123]
         distribute=True
@@ -163,8 +208,10 @@ def test_install_downloadcache(newmocksession):
     assert l[1].cwd == venv.envconfig.envlogdir
     assert "pip" in str(args[0])
     assert args[1] == "install"
-    arg = "--download-cache=" + str(venv.envconfig.downloadcache)
-    assert arg in args[2:]
+    if envdc:
+        assert venv.envconfig.downloadcache == tmpdir
+    else:
+        assert not venv.envconfig.downloadcache
     assert "dep1" in args
     assert "dep2" in args
     deps = list(filter(None, [x[1] for x in venv._getliveconfig().deps]))
@@ -175,10 +222,12 @@ def test_install_deps_indexserver(newmocksession):
         [tox]
         indexserver =
             abc = ABC
+            abc2 = ABC
         [testenv:py123]
         deps=
             dep1
             :abc:dep2
+            :abc2:dep3
     """)
     venv = mocksession.getenv('py123')
     venv.create()
@@ -188,7 +237,7 @@ def test_install_deps_indexserver(newmocksession):
 
     venv.install_deps()
     # two different index servers, two calls
-    assert len(l) == 2
+    assert len(l) == 3
     args = " ".join(l[0].args)
     assert "-i" not in args
     assert "dep1" in args
@@ -196,8 +245,11 @@ def test_install_deps_indexserver(newmocksession):
     args = " ".join(l[1].args)
     assert "-i ABC" in args
     assert "dep2" in args
+    args = " ".join(l[2].args)
+    assert "-i ABC" in args
+    assert "dep3" in args
 
-def test_install_sdist_indexserver(newmocksession, tmpdir):
+def test_installpkg_indexserver(newmocksession, tmpdir):
     mocksession = newmocksession([], """
         [tox]
         indexserver =
@@ -206,7 +258,7 @@ def test_install_sdist_indexserver(newmocksession, tmpdir):
     venv = mocksession.getenv('python')
     l = mocksession._pcalls
     p = tmpdir.ensure("distfile.tar.gz")
-    mocksession.installsdist(venv, p)
+    mocksession.installpkg(venv, p)
     # two different index servers, two calls
     assert len(l) == 1
     args = " ".join(l[0].args)
@@ -219,11 +271,21 @@ def test_install_recreate(newmocksession):
     """)
     venv = mocksession.getenv('python')
     venv.update()
-    mocksession.installsdist(venv, "xz")
+    mocksession.installpkg(venv, "xz")
     mocksession.report.expect("verbosity0", "*create*")
     venv.update()
     mocksession.report.expect("verbosity0", "*recreate*")
 
+def test_test_runtests_action_command_is_in_output(newmocksession):
+    mocksession = newmocksession([], '''
+        [testenv]
+        commands = echo foo bar
+    ''')
+    venv = mocksession.getenv('python')
+    venv.update()
+    venv.test()
+    mocksession.report.expect("verbosity0", "*runtests*commands?0? | echo foo bar")
+
 def test_install_error(newmocksession, monkeypatch):
     mocksession = newmocksession(['--recreate'], """
         [testenv]
@@ -234,6 +296,7 @@ def test_install_error(newmocksession, monkeypatch):
     venv = mocksession.getenv('python')
     venv.test()
     mocksession.report.expect("error", "*not find*qwelkqw*")
+    assert venv.status == "commands failed"
 
 def test_install_command_not_installed(newmocksession, monkeypatch):
     mocksession = newmocksession(['--recreate'], """
@@ -244,6 +307,22 @@ def test_install_command_not_installed(newmocksession, monkeypatch):
     venv = mocksession.getenv('python')
     venv.test()
     mocksession.report.expect("warning", "*test command found but not*")
+    assert venv.status == "commands failed"
+
+def test_install_command_whitelisted(newmocksession, monkeypatch):
+    mocksession = newmocksession(['--recreate'], """
+        [testenv]
+        whitelist_externals = py.test
+                              xy*
+        commands=
+            py.test
+            xyz
+    """)
+    venv = mocksession.getenv('python')
+    venv.test()
+    mocksession.report.expect("warning", "*test command found but not*",
+                              invert=True)
+    assert venv.status == "commands failed"
 
 @pytest.mark.skipif("not sys.platform.startswith('linux')")
 def test_install_command_not_installed(newmocksession):
@@ -354,7 +433,7 @@ class TestCreationConfig:
         cconfig = venv._getliveconfig()
         venv.update()
         assert not venv.path_config.check()
-        mocksession.installsdist(venv, "sdist.zip")
+        mocksession.installpkg(venv, "sdist.zip")
         assert venv.path_config.check()
         assert mocksession._pcalls
         args1 = map(str, mocksession._pcalls[0].args)
@@ -388,7 +467,7 @@ class TestCreationConfig:
         venv = VirtualEnv(envconfig, session=mocksession)
         venv.update()
         cconfig = venv._getliveconfig()
-        cconfig.distribute = False
+        cconfig.distribute = True
         cconfig.writeconfig(venv.path_config)
         mocksession._clearmocks()
         venv.update()
@@ -439,7 +518,7 @@ def test_setenv_added_to_pcall(mocksession, newconfig):
 
     venv = VirtualEnv(config.envconfigs['python'], session=mocksession)
     # import pdb; pdb.set_trace()
-    mocksession.installsdist(venv, "xyz")
+    mocksession.installpkg(venv, "xyz")
     venv.test()
 
     l = mocksession._pcalls
@@ -454,21 +533,21 @@ def test_setenv_added_to_pcall(mocksession, newconfig):
     for e in os.environ:
         assert e in env
 
-def test_install_sdist_no_upgrade(newmocksession):
+def test_installpkg_no_upgrade(newmocksession):
     mocksession = newmocksession([], "")
     venv = mocksession.getenv('python')
     venv.just_created = True
     venv.envconfig.envdir.ensure(dir=1)
-    mocksession.installsdist(venv, "whatever")
+    mocksession.installpkg(venv, "whatever")
     l = mocksession._pcalls
     assert len(l) == 1
     assert '-U' not in l[0].args
 
-def test_install_sdist_upgrade(newmocksession):
+def test_installpkg_upgrade(newmocksession):
     mocksession = newmocksession([], "")
     venv = mocksession.getenv('python')
     assert not hasattr(venv, 'just_created')
-    mocksession.installsdist(venv, "whatever")
+    mocksession.installpkg(venv, "whatever")
     l = mocksession._pcalls
     assert len(l) == 1
     assert '-U' in l[0].args
diff --git a/tests/test_z_cmdline.py b/tests/test_z_cmdline.py
index 1b397c7..6a57114 100644
--- a/tests/test_z_cmdline.py
+++ b/tests/test_z_cmdline.py
@@ -2,7 +2,7 @@ import tox
 import py
 import pytest
 import sys
-from conftest import ReportExpectMock
+from tox._pytestplugin import ReportExpectMock
 
 pytest_plugins = "pytester"
 
@@ -64,6 +64,8 @@ def test__resolve_pkg_doubledash(tmpdir, mocksession):
     res = mocksession._resolve_pkg(distshare.join("pkg-mine*"))
     assert res == p
 
+
+
 class TestSession:
     def test_make_sdist(self, initproj):
         initproj("example123-0.5", filedefs={
@@ -127,10 +129,10 @@ class TestSession:
         envs = session.venvlist
         assert len(envs) == 2
         env1, env2 = envs
-        session.setenvstatus(env1, "FAIL XYZ")
-        assert session.venvstatus[env1.path]
-        session.setenvstatus(env2, 0)
-        assert not session.venvstatus[env2.path]
+        env1.status = "FAIL XYZ"
+        assert env1.status
+        env2.status = 0
+        assert not env2.status
         session._summary()
         out, err = capfd.readouterr()
         exp = "%s: FAIL XYZ" % env1.envconfig.envname
@@ -274,7 +276,7 @@ def test_package_install_fails(cmd, initproj):
                 name='pkg123',
                 description='pkg123 project',
                 version='0.7',
-                license='GPLv2 or later',
+                license='MIT',
                 platforms=['unix', 'win32'],
                 packages=['pkg123',],
                 install_requires=['qweqwe123'],
@@ -421,7 +423,7 @@ def test_separate_sdist(cmd, initproj):
     result = cmd.run("tox", "-v", "--notest")
     assert not result.ret
     result.stdout.fnmatch_lines([
-        "*sdist-inst*%s*" % sdistfile,
+        "*inst*%s*" % sdistfile,
     ])
 
 
@@ -432,9 +434,30 @@ def test_sdist_latest(tmpdir, newconfig):
             distshare=%s
             sdistsrc={distshare}/pkg123-*
     """ % distshare)
-    distshare.ensure("pkg123-1.3.5.zip")
+    p0 = distshare.ensure("pkg123-1.3.5.zip")
     p = distshare.ensure("pkg123-1.4.5.zip")
     distshare.ensure("pkg123-1.4.5a1.zip")
     session = Session(config)
     sdist_path = session.sdist()
     assert sdist_path == p
+
+def test_installpkg(tmpdir, newconfig):
+    p = tmpdir.ensure("pkg123-1.0.zip")
+    config = newconfig(["--installpkg=%s" % p], "")
+    session = Session(config)
+    sdist_path = session.sdist()
+    assert sdist_path == p
+
+ at pytest.mark.xfail("sys.platform == 'win32'", reason="test needs better impl")
+def test_envsitepackagesdir(cmd, initproj):
+    initproj("pkg512-0.0.5", filedefs={
+        'tox.ini': """
+        [testenv]
+        commands=
+            echo X:{envsitepackagesdir}
+    """})
+    result = cmd.run("tox")
+    assert result.ret == 0
+    result.stdout.fnmatch_lines("""
+        X:*site-packages*
+    """)
diff --git a/tox.egg-info/PKG-INFO b/tox.egg-info/PKG-INFO
new file mode 100644
index 0000000..3335f00
--- /dev/null
+++ b/tox.egg-info/PKG-INFO
@@ -0,0 +1,52 @@
+Metadata-Version: 1.1
+Name: tox
+Version: 1.5.0
+Summary: virtualenv-based automation of test activities
+Home-page: http://tox.testrun.org/
+Author: holger krekel
+Author-email: holger at merlinux.eu
+License: http://opensource.org/licenses/MIT
+Description: 
+        What is Tox?
+        --------------------
+        
+        Tox as is a generic virtualenv_ management and test command line tool you can use for:
+        
+        * checking your package installs correctly with different Python versions and
+          interpreters
+        
+        * running your tests in each of the environments, configuring your test tool of choice
+        
+        * acting as a frontend to Continuous Integration servers, greatly
+          reducing boilerplate and merging CI and shell-based testing.
+        
+        For more information and the repository please checkout:
+        
+        - homepage: http://tox.testrun.org
+        
+        - repository: https://bitbucket.org/hpk42/tox
+        
+        have fun,
+        
+        
+        have fun,
+        
+        holger krekel, May 2013
+        
+        
+Platform: unix
+Platform: linux
+Platform: osx
+Platform: cygwin
+Platform: win32
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: POSIX
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Topic :: Software Development :: Testing
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Topic :: Utilities
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
diff --git a/tox.egg-info/SOURCES.txt b/tox.egg-info/SOURCES.txt
new file mode 100644
index 0000000..f8c73be
--- /dev/null
+++ b/tox.egg-info/SOURCES.txt
@@ -0,0 +1,57 @@
+CHANGELOG
+CONTRIBUTORS
+ISSUES.txt
+LICENSE
+MANIFEST.in
+README.rst
+setup.py
+tox.ini
+toxbootstrap.py
+doc/Makefile
+doc/changelog.txt
+doc/check_sphinx.py
+doc/conf.py
+doc/config-v2.txt
+doc/config.txt
+doc/examples.txt
+doc/index.txt
+doc/install.txt
+doc/links.txt
+doc/support.txt
+doc/_static/sphinxdoc.css
+doc/_templates/indexsidebar.html
+doc/_templates/layout.html
+doc/_templates/localtoc.html
+doc/announce/release-0.5.txt
+doc/announce/release-1.0.txt
+doc/announce/release-1.1.txt
+doc/announce/release-1.2.txt
+doc/announce/release-1.3.txt
+doc/announce/release-1.4.3.txt
+doc/announce/release-1.4.txt
+doc/example/basic.txt
+doc/example/general.txt
+doc/example/jenkins.txt
+doc/example/nose.txt
+doc/example/pytest.txt
+doc/example/unittest.txt
+tests/conftest.py
+tests/test_config.py
+tests/test_quickstart.py
+tests/test_venv.py
+tests/test_z_cmdline.py
+tox/__init__.py
+tox/_cmdline.py
+tox/_config.py
+tox/_exception.py
+tox/_pytestplugin.py
+tox/_quickstart.py
+tox/_venv.py
+tox/_verlib.py
+tox.egg-info/PKG-INFO
+tox.egg-info/SOURCES.txt
+tox.egg-info/dependency_links.txt
+tox.egg-info/entry_points.txt
+tox.egg-info/requires.txt
+tox.egg-info/top_level.txt
+tox.egg-info/zip-safe
\ No newline at end of file
diff --git a/tox.egg-info/dependency_links.txt b/tox.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tox.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/tox.egg-info/entry_points.txt b/tox.egg-info/entry_points.txt
new file mode 100644
index 0000000..0578f7a
--- /dev/null
+++ b/tox.egg-info/entry_points.txt
@@ -0,0 +1,4 @@
+[console_scripts]
+tox=tox:cmdline
+tox-quickstart=tox._quickstart:main
+
diff --git a/tox.egg-info/requires.txt b/tox.egg-info/requires.txt
new file mode 100644
index 0000000..279c5e3
--- /dev/null
+++ b/tox.egg-info/requires.txt
@@ -0,0 +1,2 @@
+virtualenv>=1.9.1
+py>=1.4.15
\ No newline at end of file
diff --git a/tox.egg-info/top_level.txt b/tox.egg-info/top_level.txt
new file mode 100644
index 0000000..053148f
--- /dev/null
+++ b/tox.egg-info/top_level.txt
@@ -0,0 +1 @@
+tox
diff --git a/tox.egg-info/zip-safe b/tox.egg-info/zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tox.egg-info/zip-safe
@@ -0,0 +1 @@
+
diff --git a/tox.ini b/tox.ini
index 42d93c8..81cbfa0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,21 +1,22 @@
 [tox]
-envlist=py27,py26,py25,py31,py32,docs
-indexserver =
-    testrun = http://pypi.testrun.org
-    pypi = http://pypi.python.org/simple
+envlist=py27,py26,py25,py32,py33,docs,pypy
 
 [testenv:X]
 commands=echo {posargs}
 
 [testenv]
-commands=py.test --junitxml={envlogdir}/junit-{envname}.xml {posargs}
-deps=pytest
-     py
+commands=py.test --instafail --junitxml={envlogdir}/junit-{envname}.xml {posargs}
+deps=pytest==2.3.4
+     pytest-instafail
+
+[testenv:py25]
+setenvs =
+    PIP_INSECURE=True
 
 [testenv:docs]
 basepython=python
 changedir=doc
-deps=:pypi:sphinx
+deps=sphinx
      {[testenv]deps}
 commands=
     py.test -v \
diff --git a/tox/__init__.py b/tox/__init__.py
index 30fb04a..02f0744 100644
--- a/tox/__init__.py
+++ b/tox/__init__.py
@@ -1,5 +1,5 @@
 #
-__version__ = '1.4.2'
+__version__ = '1.5.0'
 
 class exception:
     class Error(Exception):
diff --git a/tox/_cmdline.py b/tox/_cmdline.py
index 4d78dc7..e34d84f 100644
--- a/tox/_cmdline.py
+++ b/tox/_cmdline.py
@@ -81,7 +81,7 @@ class Action(object):
             f.write("actionid=%s\nmsg=%s\ncmdargs=%r\nenv=%s\n" %(
                     self.id, self.msg, args, env))
             f.flush()
-            outpath = py.path.local(f.name)
+            self.popen_outpath = outpath = py.path.local(f.name)
         if cwd is None:
             # XXX cwd = self.session.config.cwd
             cwd = py.path.local()
@@ -92,7 +92,7 @@ class Action(object):
         popen.action = self
         self._popenlist.append(popen)
         try:
-            self.report.logpopen(popen)
+            self.report.logpopen(popen, env=env)
             try:
                 out, err = popen.communicate()
             except KeyboardInterrupt:
@@ -105,10 +105,11 @@ class Action(object):
         if ret:
             invoked = " ".join(map(str, popen.args))
             if outpath:
-                self.report.error("invocation failed, logfile: %s" % outpath)
+                self.report.error("invocation failed, logfile: %s" %
+                                  outpath)
                 self.report.error(outpath.read())
                 raise tox.exception.InvocationError(
-                    "%s (see %s)" %(invoked, outpath))
+                    "%s (see %s)" %(invoked, outpath), ret)
             else:
                 raise tox.exception.InvocationError("%r" %(invoked, ))
         return out
@@ -119,6 +120,14 @@ class Action(object):
             if sys.platform != "win32" and isinstance(arg, py.path.local):
                 arg = cwd.bestrelpath(arg)
             newargs.append(str(arg))
+
+        #subprocess does not always take kindly to .py scripts
+        #so adding the interpreter here.
+        if sys.platform == "win32":
+            ext = os.path.splitext(str(newargs[0]))[1].lower()
+            if ext == '.py' and self.venv:
+                newargs = [str(self.venv.getcommandpath())] + newargs
+
         return newargs
 
     def _popen(self, args, cwd, stdout, stderr, env=None):
@@ -128,14 +137,17 @@ class Action(object):
         return self.session.popen(args, shell=False, cwd=str(cwd),
             stdout=stdout, stderr=stderr, env=env)
 
+
+
 class Reporter(object):
     actionchar = "-"
     def __init__(self, session):
         self.tw = py.io.TerminalWriter()
         self.session = session
+        self._reportedlines = []
         #self.cumulated_time = 0.0
 
-    def logpopen(self, popen):
+    def logpopen(self, popen, env):
         """ log information about the action.popen() created process. """
         cmd = " ".join(map(str, popen.args))
         if popen.outpath:
@@ -170,7 +182,7 @@ class Reporter(object):
 
 
     def keyboard_interrupt(self):
-        self.tw.line("KEYBOARDINTERRUPT", red=True)
+        self.error("KEYBOARDINTERRUPT")
 
 #    def venv_installproject(self, venv, pkg):
 #        self.logline("installing to %s: %s" % (venv.envconfig.envname, pkg))
@@ -195,26 +207,26 @@ class Reporter(object):
         self.logline("ERROR: " + msg, red=True)
 
     def logline(self, msg, **opts):
+        self._reportedlines.append(msg)
         self.tw.line("%s" % msg, **opts)
 
     def verbosity0(self, msg, **opts):
         if self.session.config.option.verbosity >= 0:
-            self.tw.line("%s" % msg, **opts)
+            self.logline("%s" % msg, **opts)
 
     def verbosity1(self, msg, **opts):
         if self.session.config.option.verbosity >= 1:
-            self.tw.line("%s" % msg, **opts)
+            self.logline("%s" % msg, **opts)
 
     def verbosity2(self, msg, **opts):
         if self.session.config.option.verbosity >= 2:
-            self.tw.line("%s" % msg, **opts)
+            self.logline("%s" % msg, **opts)
 
     #def log(self, msg):
     #    py.builtin.print_(msg, file=sys.stderr)
 
 
 class Session:
-    passthroughpossible = True
 
     def __init__(self, config, popen=subprocess.Popen, Report=Reporter):
         self.config = config
@@ -224,7 +236,6 @@ class Session:
         config.logdir.ensure(dir=1)
         #self.report.using("logdir %s" %(self.config.logdir,))
         self.report.using("tox.ini: %s" %(self.config.toxinipath,))
-        self.venvstatus = {}
         self._spec2pkg = {}
         self._name2venv = {}
         try:
@@ -256,12 +267,11 @@ class Session:
         return action
 
     def runcommand(self):
-        #tw.sep("-", "tox info from %s" % self.options.configfile)
-        self.report.using("tox-%s from %s" %(tox.__version__, tox.__file__))
+        self.report.using("tox-%s from %s" %(tox.__version__,
+                                             tox.__file__))
         if self.config.minversion:
             minversion = NormalizedVersion(self.config.minversion)
             toxversion = NormalizedVersion(tox.__version__)
-            #self.report.using("requires at least %s" %(minversion,))
             if toxversion < minversion:
                 self.report.error(
                     "tox version is %s, required is at least %s" %(
@@ -269,6 +279,8 @@ class Session:
                 raise SystemExit(1)
         if self.config.option.showconfig:
             self.showconfig()
+        elif self.config.option.listenvs:
+            self.showenvs()
         else:
             return self.subcommand_test()
 
@@ -282,9 +294,6 @@ class Session:
             target.dirpath().ensure(dir=1)
             src.copy(target)
 
-    def setenvstatus(self, venv, msg):
-        self.venvstatus[venv.path] = msg
-
     def _makesdist(self):
         setup = self.config.setupdir.join("setup.py")
         if not setup.check():
@@ -307,33 +316,36 @@ class Session:
     def setupenv(self, venv):
         action = self.newaction(venv, "getenv", venv.envconfig.envdir)
         with action:
-            self.venvstatus[venv.path] = 0
+            venv.status = 0
             try:
                 status = venv.update(action=action)
             except tox.exception.InvocationError:
                 status = sys.exc_info()[1]
             if status:
-                self.setenvstatus(venv, status)
+                venv.status = status
                 self.report.error(str(status))
                 return False
             return True
 
-    def installsdist(self, venv, sdist_path):
-        action = self.newaction(venv, "sdist-install", sdist_path)
+    def installpkg(self, venv, sdist_path):
+        action = self.newaction(venv, "installpkg", sdist_path)
         with action:
             try:
-                venv.install_sdist(sdist_path, action)
+                venv.installpkg(sdist_path, action)
                 return True
             except tox.exception.InvocationError:
-                self.setenvstatus(venv, sys.exc_info()[1])
+                venv.status = sys.exc_info()[1]
                 return False
 
     def sdist(self):
-        if not self.config.option.sdistonly and self.config.sdistsrc:
-            self.report.info("using sdistfile %r, skipping 'sdist' activity " %
-                str(self.config.sdistsrc))
-            sdist_path = self.config.sdistsrc
+        if not self.config.option.sdistonly and (self.config.sdistsrc or
+            self.config.option.installpkg):
+            sdist_path = self.config.option.installpkg
+            if not sdist_path:
+                sdist_path = self.config.sdistsrc
             sdist_path = self._resolve_pkg(sdist_path)
+            self.report.info("using package %r, skipping 'sdist' activity " %
+                str(sdist_path))
         else:
             try:
                 sdist_path = self._makesdist()
@@ -357,25 +369,24 @@ class Session:
             return
         for venv in self.venvlist:
             if self.setupenv(venv):
-                self.installsdist(venv, sdist_path)
+                self.installpkg(venv, sdist_path)
                 self.runtestenv(venv, sdist_path)
         retcode = self._summary()
         return retcode
 
     def runtestenv(self, venv, sdist_path, redirect=False):
         if not self.config.option.notest:
-            if self.venvstatus[venv.path]:
+            if venv.status:
                 return
-            if venv.test(redirect=redirect):
-                self.setenvstatus(venv, "commands failed")
+            venv.test(redirect=redirect)
         else:
-            self.setenvstatus(venv, "skipped tests")
+            venv.status = "skipped tests"
 
     def _summary(self):
         self.report.startsummary()
         retcode = 0
         for venv in self.venvlist:
-            status = self.venvstatus[venv.path]
+            status = venv.status
             if status and status != "skipped tests":
                 msg = "  %s: %s" %(venv.envconfig.envname, str(status))
                 self.report.error(msg)
@@ -383,7 +394,8 @@ class Session:
             else:
                 if not status:
                     status = "commands succeeded"
-                self.report.good("  %s: %s" %(venv.envconfig.envname, status))
+                self.report.good("  %s: %s" %(venv.envconfig.envname,
+                                              status))
         if not retcode:
             self.report.good("  congratulations :)")
         return retcode
@@ -413,6 +425,10 @@ class Session:
             self.report.line("  envdir=    %s" % envconfig.envdir)
             self.report.line("  downloadcache=%s" % envconfig.downloadcache)
 
+    def showenvs(self):
+        for env in self.config.envlist:
+            self.report.line("%s" % env)
+
     def info_versions(self):
         versions = ['tox-%s' % tox.__version__]
         version = py.process.cmdexec("virtualenv --version")
diff --git a/tox/_config.py b/tox/_config.py
index 80eb38e..78d5fcd 100644
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -1,17 +1,25 @@
 import argparse
+import distutils.sysconfig
 import os
 import sys
 import re
 import shlex
 import string
+import subprocess
+import textwrap
 
 import py
 
 import tox
 
+
 defaultenvs = {'jython': 'jython', 'pypy': 'pypy'}
-for _name in "py24,py25,py26,py27,py30,py31,py32,py33".split(","):
-    defaultenvs[_name] = "python%s.%s" %(_name[2], _name[3])
+for _name in "py,py24,py25,py26,py27,py30,py31,py32,py33,py34".split(","):
+    if _name == "py":
+        basepython = sys.executable
+    else:
+        basepython = "python" + ".".join(_name[2:4])
+    defaultenvs[_name] = basepython
 
 def parseconfig(args=None, pkg=None):
     if args is None:
@@ -20,7 +28,22 @@ def parseconfig(args=None, pkg=None):
     opts = parser.parse_args(args)
     config = Config()
     config.option = opts
-    parseini(config)
+    basename = config.option.configfile
+    if os.path.isabs(basename):
+        inipath = py.path.local(basename)
+    else:
+        for path in py.path.local().parts(reverse=True):
+            inipath = path.join(basename)
+            if inipath.check():
+                break
+        else:
+            feedback("toxini file %r not found" %(basename), sysexit=True)
+    try:
+        parseini(config, inipath)
+    except tox.exception.InterpreterNotFound:
+        exn = sys.exc_info()[1]
+        # Use stdout to match test expectations
+        py.builtin.print_("ERROR: " + str(exn))
     return config
 
 def feedback(msg, sysexit=False):
@@ -55,9 +78,11 @@ def prepare_parse(pkgname):
         help="increase verbosity of reporting output.")
     parser.add_argument("--showconfig", action="store_true", dest="showconfig",
         help="show configuration information. ")
+    parser.add_argument("-l", "--listenvs", action="store_true",
+        dest="listenvs", help="show list of test environments")
     parser.add_argument("-c", action="store", default="tox.ini",
         dest="configfile",
-        help="use the specified config file.")
+        help="use the specified config file name.")
     parser.add_argument("-e", action="store", dest="env",
         metavar="envlist",
         help="work against specified environments (ALL selects all).")
@@ -65,6 +90,8 @@ def prepare_parse(pkgname):
         help="skip invoking test commands.")
     parser.add_argument("--sdistonly", action="store_true", dest="sdistonly",
         help="only perform the sdist packaging activity.")
+    parser.add_argument("--installpkg", action="store", default=None,
+        help="use specified package for installation into venv")
     parser.add_argument('-i', action="append",
         dest="indexurl", metavar="URL",
         help="set indexserver url (if URL is of form name=url set the "
@@ -87,7 +114,8 @@ class VenvConfig:
 
     @property
     def envbindir(self):
-        if sys.platform == "win32" and "jython" not in self.basepython:
+        if (sys.platform == "win32" and "jython" not in self.basepython
+                                    and "pypy" not in self.basepython):
             return self.envdir.join("Scripts")
         else:
             return self.envdir.join("bin")
@@ -100,17 +128,52 @@ class VenvConfig:
             name = "python"
         return self.envbindir.join(name)
 
+    # no @property to avoid early calling (see callable(subst[key]) checks)
+    def envsitepackagesdir(self):
+        print_envsitepackagesdir = textwrap.dedent("""
+        import sys
+        from distutils.sysconfig import get_python_lib
+        sys.stdout.write(get_python_lib(prefix=sys.argv[1]))
+        """)
+
+        exe = self.getsupportedinterpreter()
+        # can't use check_output until py27
+        proc = subprocess.Popen(
+            [str(exe), '-c', print_envsitepackagesdir, str(self.envdir)],
+            stdout=subprocess.PIPE)
+        odata, edata = proc.communicate()
+        if proc.returncode:
+            raise tox.exception.UnsupportedInterpreter(
+                "Error getting site-packages from %s" % self.basepython)
+        return odata
+
+    def getconfigexecutable(self):
+        from tox._venv import find_executable
+
+        python = self.basepython
+        if not python:
+            python = sys.executable
+        x = find_executable(str(python))
+        if x:
+            x = x.realpath()
+        return x
+
+    def getsupportedinterpreter(self):
+        if sys.platform == "win32" and self.basepython and \
+                "jython" in self.basepython:
+            raise tox.exception.UnsupportedInterpreter(
+                "Jython/Windows does not support installing scripts")
+        config_executable = self.getconfigexecutable()
+        if not config_executable:
+            raise tox.exception.InterpreterNotFound(self.basepython)
+        return config_executable
 testenvprefix = "testenv:"
 
 class parseini:
-    def __init__(self, config):
-        config.option.configfile = py.path.local(config.option.configfile)
-        config.toxinipath = config.option.configfile
+    def __init__(self, config, inipath):
+        config.toxinipath = inipath
         config.toxinidir = toxinidir = config.toxinipath.dirpath()
 
-        if not config.toxinipath.check():
-            feedback("toxini file %r does not exist" %(
-                str(config.toxinipath)), sysexit=True)
         self._cfg = py.iniconfig.IniConfig(config.toxinipath)
         config._cfg = self._cfg
         self.config = config
@@ -140,9 +203,10 @@ class parseini:
             name, url = map(lambda x: x.strip(), line.split("=", 1))
             config.indexserver[name] = IndexServerConfig(name, url)
 
+        override = False
         if config.option.indexurl:
             for urldef in config.option.indexurl:
-                m = re.match(r"(\w+)=(\S+)", urldef)
+                m = re.match(r"\W*(\w+)=(\S+)", urldef)
                 if m is None:
                     url = urldef
                     name = "default"
@@ -150,7 +214,14 @@ class parseini:
                     name, url = m.groups()
                     if not url:
                         url = None
-                config.indexserver[name].url = url
+                if name != "ALL":
+                    config.indexserver[name].url = url
+                else:
+                    override = url
+        # let ALL override all existing entries
+        if override:
+            for name in config.indexserver:
+                config.indexserver[name] = IndexServerConfig(name, override)
 
         reader.addsubstitions(toxworkdir=config.toxworkdir)
         config.distdir = reader.getpath(toxsection, "distdir",
@@ -195,7 +266,8 @@ class parseini:
             bp = sys.executable
         vc.basepython = reader.getdefault(section, "basepython", bp)
         reader.addsubstitions(envdir=vc.envdir, envname=vc.envname,
-                              envbindir=vc.envbindir, envpython=vc.envpython)
+                              envbindir=vc.envbindir, envpython=vc.envpython,
+                              envsitepackagesdir=vc.envsitepackagesdir)
         vc.envtmpdir = reader.getpath(section, "tmpdir", "{envdir}/tmp")
         vc.envlogdir = reader.getpath(section, "envlogdir", "{envdir}/log")
         reader.addsubstitions(envlogdir=vc.envlogdir, envtmpdir=vc.envtmpdir)
@@ -219,6 +291,8 @@ class parseini:
             vc.setenv = None
 
         vc.commands = reader.getargvlist(section, "commands")
+        vc.whitelist_externals = reader.getlist(section,
+                                                "whitelist_externals")
         vc.deps = []
         for depline in reader.getlist(section, "deps"):
             m = re.match(r":(\w+):\s*(\S+)", depline)
@@ -229,14 +303,14 @@ class parseini:
                 name = depline.strip()
                 ixserver = None
             vc.deps.append(DepConfig(name, ixserver))
-        vc.distribute = reader.getbool(section, "distribute", True)
+        vc.distribute = reader.getbool(section, "distribute", False)
         vc.sitepackages = reader.getbool(section, "sitepackages", False)
-        downloadcache = reader.getdefault(section, "downloadcache")
-        if downloadcache is None:
-            downloadcache = os.environ.get("PIP_DOWNLOAD_CACHE", "")
-            if not downloadcache:
-                downloadcache = self.config.toxworkdir.join("_download")
-        vc.downloadcache = py.path.local(downloadcache)
+        vc.downloadcache = None
+        downloadcache = os.environ.get("PIP_DOWNLOAD_CACHE", None)
+        if not downloadcache:
+            downloadcache = reader.getdefault(section, "downloadcache")
+        if downloadcache:
+            vc.downloadcache = py.path.local(downloadcache)
         return vc
 
     def _getenvlist(self, reader, toxsection):
@@ -273,6 +347,16 @@ class IndexServerConfig:
         self.name = name
         self.url = url
 
+RE_ITEM_REF = re.compile(
+    '''
+    [{]
+    (?:(?P<sub_type>[^[:{}]+):)?    # optional sub_type for special rules
+    (?P<substitution_value>[^{}]*)  # substitution key
+    [}]
+    ''',
+    re.VERBOSE)
+
+
 class IniReader:
     def __init__(self, cfgparser, fallbacksections=None):
         self._cfg = cfgparser
@@ -339,7 +423,6 @@ class IniReader:
 
     def _processcommand(self, command):
         posargs = self._subs.get('_posargs', None)
-        pat = r'\{(?:(?P<sub_type>[^:]+):)?(?P<substitution_value>.*)\}'
         words = list(CommandParser(command).words())
         new_command = ''
         for word in words:
@@ -348,9 +431,9 @@ class IniReader:
                     new_command += ' '.join(posargs)
                 continue
 
-            new_word = re.sub(pat, self._replace_match, word)
+            new_word = self._replace(word, quote=True)
             # two passes; we might have substitutions in the result
-            new_word = re.sub(pat, self._replace_match, new_word)
+            new_word = self._replace(new_word, quote=True)
             new_command += new_word
 
         return shlex.split(new_command.strip())
@@ -392,35 +475,7 @@ class IniReader:
         #print "getdefault", section, name, "returned", repr(x)
         return x
 
-    def _sub(self, match):
-        key = match.group(0)[1:-1]
-        if key.startswith("env:"):
-            envkey = key[4:]
-            if envkey not in os.environ:
-                raise tox.exception.ConfigError(
-                    "substitution %r: %r not found in environment" %
-                    (key, envkey))
-            return os.environ[envkey]
-        if key not in self._subs:
-            if key.startswith("[") and "]" in key:
-                i = key.find("]")
-                section, item = key[1:i], key[i+1:]
-                if section in self._cfg and item in self._cfg[section]:
-                    if (section, item) in self._subststack:
-                        raise ValueError('%s already in %s' %(
-                                (section, item), self._subststack))
-                    x = str(self._cfg[section][item])
-                    self._subststack.append((section, item))
-                    try:
-                        return self._replace(x)
-                    finally:
-                        self._subststack.pop()
-
-            raise tox.exception.ConfigError(
-                "substitution key %r not found" % key)
-        return str(self._subs[key])
-
-    def _replace_posargs(self, match):
+    def _replace_posargs(self, match, quote):
         return self._do_replace_posargs(lambda: match.group('substitution_value'))
 
     def _do_replace_posargs(self, value_func):
@@ -435,7 +490,7 @@ class IniReader:
 
         return ''
 
-    def _replace_env(self, match):
+    def _replace_env(self, match, quote):
         envkey = match.group('substitution_value')
         if not envkey:
             raise tox.exception.ConfigError(
@@ -448,18 +503,41 @@ class IniReader:
 
         return os.environ[envkey]
 
-    def _replace_substitution(self, match):
+    def _substitute_from_other_section(self, key, quote):
+        if key.startswith("[") and "]" in key:
+            i = key.find("]")
+            section, item = key[1:i], key[i+1:]
+            if section in self._cfg and item in self._cfg[section]:
+                if (section, item) in self._subststack:
+                    raise ValueError('%s already in %s' %(
+                            (section, item), self._subststack))
+                x = str(self._cfg[section][item])
+                self._subststack.append((section, item))
+                try:
+                    return self._replace(x, quote=quote)
+                finally:
+                    self._subststack.pop()
+
+        raise tox.exception.ConfigError(
+            "substitution key %r not found" % key)
+
+    def _replace_substitution(self, match, quote):
         sub_key = match.group('substitution_value')
-        if sub_key not in self._subs:
-            raise tox.exception.ConfigError(
-                "substitution key %r not found" % sub_key)
-        return '"%s"' % str(self._subs[sub_key]).replace('"', r'\"')
+        val = self._subs.get(sub_key, None)
+        if val is None:
+            val = self._substitute_from_other_section(sub_key, quote)
+        if py.builtin.callable(val):
+            val = val()
+        if quote:
+            return '"%s"' % str(val).replace('"', r'\"')
+        else:
+            return str(val)
 
     def _is_bare_posargs(self, groupdict):
         return groupdict.get('substitution_value', None) == 'posargs' \
                and not groupdict.get('sub_type')
 
-    def _replace_match(self, match):
+    def _replace_match(self, match, quote):
         g = match.groupdict()
 
         # special case: posargs. If there is a 'posargs' substitution value
@@ -482,11 +560,23 @@ class IniReader:
         except KeyError:
             raise tox.exception.ConfigError("No support for the %s substitution type" % sub_type)
 
-        return handler(match)
+        # quoting is done in handlers, as at least posargs handling is special:
+        #  all of its arguments are inserted as separate parameters
+        return handler(match, quote)
 
-    def _replace(self, x, rexpattern = re.compile("\{.+?\}")):
+    def _replace_match_quote(self, match):
+        return self._replace_match(match, quote=True)
+    def _replace_match_no_quote(self, match):
+        return self._replace_match(match, quote=False)
+
+    def _replace(self, x, rexpattern=RE_ITEM_REF, quote=False):
+        # XXX is rexpattern used by callers? can it be removed?
         if '{' in x:
-            return rexpattern.sub(self._sub, x)
+            if quote:
+                replace_func = self._replace_match_quote
+            else:
+                replace_func = self._replace_match_no_quote
+            return rexpattern.sub(replace_func, x)
         return x
 
     def _parse_command(self, command):
diff --git a/tests/conftest.py b/tox/_pytestplugin.py
similarity index 94%
copy from tests/conftest.py
copy to tox/_pytestplugin.py
index 51bc0a2..1c0024b 100644
--- a/tests/conftest.py
+++ b/tox/_pytestplugin.py
@@ -1,4 +1,4 @@
-import py
+import pytest, py
 import tox
 import os
 import sys
@@ -18,8 +18,7 @@ def pytest_configure():
 def pytest_report_header():
     return "tox comes from: %r" % (tox.__file__)
 
-def pytest_funcarg__newconfig(request):
-    tmpdir = request.getfuncargvalue("tmpdir")
+def pytest_funcarg__newconfig(request, tmpdir):
     def newconfig(args, source=None):
         if source is None:
             source = args
@@ -34,12 +33,6 @@ def pytest_funcarg__newconfig(request):
             old.chdir()
     return newconfig
 
-def pytest_funcarg__tmpdir(request):
-    tmpdir = request.getfuncargvalue("tmpdir")
-    request.addfinalizer(py.path.local().chdir)
-    tmpdir.chdir()
-    return tmpdir
-
 def pytest_funcarg__cmd(request):
     return Cmd(request)
 
@@ -106,7 +99,8 @@ class ReportExpectMock:
 
 class pcallMock:
     def __init__(self, args, cwd, env, stdout, stderr, shell):
-        self.args = args
+        self.arg0 = args[0]
+        self.args = args[1:]
         self.cwd = cwd
         self.env = env
         self.stdout = stdout
@@ -249,9 +243,9 @@ class LineMatcher:
             else:
                 assert line == nextline
 
-def pytest_funcarg__initproj(request):
+ at pytest.fixture
+def initproj(request, tmpdir):
     """ create a factory function for creating example projects. """
-    tmpdir = request.getfuncargvalue("tmpdir")
     def initproj(name, filedefs=None):
         if filedefs is None:
             filedefs = {}
@@ -268,14 +262,18 @@ def pytest_funcarg__initproj(request):
                     name='%(name)s',
                     description='%(name)s project',
                     version='%(version)s',
-                    license='GPLv2 or later',
+                    license='MIT',
                     platforms=['unix', 'win32'],
                     packages=['%(name)s', ],
                 )
             ''' % locals()})
         if name not in filedefs:
             create_files(base, {name:
-                {'__init__.py': '__version__ = %s' % version}})
+                {'__init__.py': '__version__ = %r' % version}})
+        manifestlines = []
+        for p in base.visit(lambda x: x.check(file=1)):
+            manifestlines.append("include %s" % p.relto(base))
+        create_files(base, {"MANIFEST.in": "\n".join(manifestlines)})
         print ("created project in %s" %(base,))
         base.chdir()
     return initproj
diff --git a/tox/_quickstart.py b/tox/_quickstart.py
new file mode 100644
index 0000000..4b39d04
--- /dev/null
+++ b/tox/_quickstart.py
@@ -0,0 +1,266 @@
+# -*- coding: utf-8 -*-
+"""
+    tox._quickstart
+    ~~~~~~~~~~~~~~~~~
+
+    Command-line script to quickly setup tox.ini for a Python project
+
+    This file was heavily inspired by and uses code from ``sphinx-quickstart``
+    in the BSD-licensed `Sphinx project`_.
+
+    .. Sphinx project_: http://sphinx.pocoo.org/
+
+    License for Sphinx
+    ==================
+
+    Copyright (c) 2007-2011 by the Sphinx team (see AUTHORS file).
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are
+    met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+
+import sys
+from os import path
+from codecs import open
+
+TERM_ENCODING = getattr(sys.stdin, 'encoding', None)
+
+from tox import __version__
+
+# function to get input from terminal -- overridden by the test suite
+try:
+    # this raw_input is not converted by 2to3
+    term_input = raw_input
+except NameError:
+    term_input = input
+
+
+all_envs = ['py24', 'py25', 'py26', 'py27', 'py30', 'py31', 'py32', 'py33', 'pypy', 'jython']
+
+PROMPT_PREFIX = '> '
+
+QUICKSTART_CONF = '''\
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = %(envlist)s
+
+[testenv]
+commands = %(commands)s
+deps = %(deps)s
+'''
+
+
+class ValidationError(Exception):
+    """Raised for validation errors."""
+
+def nonempty(x):
+    if not x:
+        raise ValidationError("Please enter some text.")
+    return x
+
+def choice(*l):
+    def val(x):
+        if x not in l:
+            raise ValidationError('Please enter one of %s.' % ', '.join(l))
+        return x
+    return val
+
+def boolean(x):
+    if x.upper() not in ('Y', 'YES', 'N', 'NO'):
+        raise ValidationError("Please enter either 'y' or 'n'.")
+    return x.upper() in ('Y', 'YES')
+
+def suffix(x):
+    if not (x[0:1] == '.' and len(x) > 1):
+        raise ValidationError("Please enter a file suffix, "
+                              "e.g. '.rst' or '.txt'.")
+    return x
+
+def ok(x):
+    return x
+
+
+def do_prompt(d, key, text, default=None, validator=nonempty):
+    while True:
+        if default:
+            prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default)
+        else:
+            prompt = PROMPT_PREFIX + text + ': '
+        x = term_input(prompt)
+        if default and not x:
+            x = default
+        if sys.version_info < (3, ) and not isinstance(x, unicode):
+            # for Python 2.x, try to get a Unicode string out of it
+            if x.decode('ascii', 'replace').encode('ascii', 'replace') != x:
+                if TERM_ENCODING:
+                    x = x.decode(TERM_ENCODING)
+                else:
+                    print('* Note: non-ASCII characters entered '
+                          'and terminal encoding unknown -- assuming '
+                          'UTF-8 or Latin-1.')
+                    try:
+                        x = x.decode('utf-8')
+                    except UnicodeDecodeError:
+                        x = x.decode('latin1')
+        try:
+            x = validator(x)
+        except ValidationError:
+            err = sys.exc_info()[1]
+            print('* ' + str(err))
+            continue
+        break
+    d[key] = x
+
+
+def ask_user(d):
+    """Ask the user for quickstart values missing from *d*.
+
+    """
+
+    print('Welcome to the Tox %s quickstart utility.' % __version__)
+    print('''
+This utility will ask you a few questions and then generate a simple tox.ini
+file to help get you started using tox.
+
+Please enter values for the following settings (just press Enter to
+accept a default value, if one is given in brackets).''')
+
+    sys.stdout.write('\n')
+
+    print('''
+What Python versions do you want to test against? Choices:
+    [1] py27
+    [2] py27, py33
+    [3] (All versions) %s
+    [4] Choose each one-by-one''' % ', '.join(all_envs))
+    do_prompt(d, 'canned_pyenvs', 'Enter the number of your choice',
+        '3', choice('1', '2', '3', '4'))
+
+    if d['canned_pyenvs'] == '1':
+        d['py27'] = True
+    elif d['canned_pyenvs'] == '2':
+        for pyenv in ('py27', 'py33'):
+            d[pyenv] = True
+    elif d['canned_pyenvs'] == '3':
+        for pyenv in all_envs:
+            d[pyenv] = True
+    elif d['canned_pyenvs'] == '4':
+        for pyenv in all_envs:
+            if pyenv not in d:
+                do_prompt(d, pyenv, 'Test your project with %s (Y/n)' % pyenv, 'Y', boolean)
+
+    print('''
+What command should be used to test your project -- examples:
+    - py.test
+    - python setup.py test
+    - nosetests package.module
+    - trial package.module''')
+    do_prompt(d, 'commands', 'Command to run to test project', '{envpython} setup.py test')
+
+    default_deps = ' '
+    if 'py.test' in d['commands']:
+        default_deps = 'pytest'
+    if 'nosetests' in d['commands']:
+        default_deps = 'nose'
+    if 'trial' in d['commands']:
+        default_deps = 'twisted'
+
+    print('''
+What dependencies does your project have?''')
+    do_prompt(d, 'deps', 'Comma-separated list of dependencies', default_deps)
+
+
+def process_input(d):
+    d['envlist'] = ', '.join([env for env in all_envs if d.get(env) is True])
+    d['deps'] = '\n' + '\n'.join(['    %s' % dep.strip()
+                                for dep in d['deps'].split(',')])
+
+    return d
+
+def rtrim_right(text):
+    lines = []
+    for line in text.split("\n"):
+        lines.append(line.rstrip())
+    return "\n".join(lines)
+
+def generate(d, overwrite=True, silent=False):
+    """Generate project based on values in *d*."""
+
+    conf_text = QUICKSTART_CONF % d
+    conf_text = rtrim_right(conf_text)
+
+    def write_file(fpath, mode, content):
+        print('Creating file %s.' % fpath)
+        f = open(fpath, mode, encoding='utf-8')
+        try:
+            f.write(content)
+        finally:
+            f.close()
+
+    sys.stdout.write('\n')
+
+    fpath = 'tox.ini'
+
+    if path.isfile(fpath) and not overwrite:
+        print('File %s already exists.' % fpath)
+        do_prompt(d, 'fpath', 'Alternative path to write tox.ini contents to', 'tox-generated.ini')
+        fpath = d['fpath']
+
+    write_file(fpath, 'w', conf_text)
+
+    if silent:
+        return
+    sys.stdout.write('\n')
+    print('Finished: A tox.ini file has been created. For information on this file, see http://tox.testrun.org/latest/config.html')
+    print('''
+Execute `tox` to test your project.
+''')
+
+
+def main(argv=sys.argv):
+    d = {}
+
+    if len(argv) > 3:
+        print('Usage: tox-quickstart [root]')
+        sys.exit(1)
+    elif len(argv) == 2:
+        d['path'] = argv[1]
+
+    try:
+        ask_user(d)
+    except (KeyboardInterrupt, EOFError):
+        print()
+        print('[Interrupted.]')
+        return
+
+    d = process_input(d)
+    generate(d, overwrite=False)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tox/_venv.py b/tox/_venv.py
index 2574c21..5008c00 100644
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -1,5 +1,5 @@
 from __future__ import with_statement
-import sys, os
+import sys, os, re
 import py
 import tox
 from tox._config import DepConfig
@@ -74,21 +74,38 @@ class VirtualEnv(object):
             p = cwd.join(name)
             if p.check():
                 return str(p)
+        p = None
+        if venv:
+            p = py.path.local.sysfind(name, paths=[self.envconfig.envbindir])
+        if p is not None:
+            return p
         p = py.path.local.sysfind(name)
         if p is None:
-            raise tox.exception.InvocationError("could not find executable %r"
-                % (name,))
-        if p.relto(self.envconfig.envdir):
-            return p
+            raise tox.exception.InvocationError(
+                    "could not find executable %r" % (name,))
+        # p is not found in virtualenv script/bin dir
         if venv:
-            self.session.report.warning(
-                "test command found but not installed in testenv\n"
-                "  cmd: %s\n"
-                "  env: %s\n"
-                "Maybe forgot to specify a dependency?" % (p,
-                self.envconfig.envdir))
+            if not self.is_allowed_external(p):
+                self.session.report.warning(
+                    "test command found but not installed in testenv\n"
+                    "  cmd: %s\n"
+                    "  env: %s\n"
+                    "Maybe forgot to specify a dependency?" % (p,
+                    self.envconfig.envdir))
         return str(p) # will not be rewritten for reporting
 
+    def is_allowed_external(self, p):
+        tryadd = [""]
+        if sys.platform == "win32":
+            tryadd += [os.path.normcase(x)
+                        for x in os.environ['PATHEXT'].split(os.pathsep)]
+            p = py.path.local(os.path.normcase(str(p)))
+        for x in self.envconfig.whitelist_externals:
+            for add in tryadd:
+                if p.fnmatch(x + add):
+                    return True
+        return False
+
     def _ispython3(self):
         return "python3" in str(self.envconfig.basepython)
 
@@ -146,23 +163,10 @@ class VirtualEnv(object):
         return l
 
     def getconfigexecutable(self):
-        python = self.envconfig.basepython
-        if not python:
-            python = sys.executable
-        x = find_executable(str(python))
-        if x:
-            x = x.realpath()
-        return x
+        return self.envconfig.getconfigexecutable()
 
     def getsupportedinterpreter(self):
-        if sys.platform == "win32" and self.envconfig.basepython and \
-                "jython" in self.envconfig.basepython:
-            raise tox.exception.UnsupportedInterpreter(
-                "Jython/Windows does not support installing scripts")
-        config_executable = self.getconfigexecutable()
-        if not config_executable:
-            raise tox.exception.InterpreterNotFound(self.envconfig.basepython)
-        return config_executable
+        return self.envconfig.getsupportedinterpreter()
 
     def create(self, action=None):
         #if self.getcommandpath("activate").dirpath().check():
@@ -175,8 +179,10 @@ class VirtualEnv(object):
         venvscript = path.rstrip("co")
         #venvscript = py.path.local(tox.__file__).dirpath("virtualenv.py")
         args = [config_interpreter, venvscript]
-        if not self._ispython3() and self.envconfig.distribute:
-            args.append('--distribute')
+        if self.envconfig.distribute:
+            args.append("--distribute")
+        else:
+            args.append("--setuptools")
         if self.envconfig.sitepackages:
             args.append('--system-site-packages')
         #if sys.platform == "win32":
@@ -191,14 +197,14 @@ class VirtualEnv(object):
         self._pcall(args, venv=False, action=action, cwd=basepath)
         self.just_created = True
 
-    def install_sdist(self, sdistpath, action):
+    def installpkg(self, sdistpath, action):
         assert action is not None
         if getattr(self, 'just_created', False):
-            action.setactivity("sdist-inst", sdistpath)
+            action.setactivity("inst", sdistpath)
             self._getliveconfig().writeconfig(self.path_config)
             extraopts = []
         else:
-            action.setactivity("sdist-reinst", sdistpath)
+            action.setactivity("inst-nodeps", sdistpath)
             extraopts = ['-U', '--no-deps']
         self._install([sdistpath], extraopts=extraopts, action=action)
 
@@ -224,6 +230,9 @@ class VirtualEnv(object):
 
     def pip_install(self, args, indexserver=None, action=None):
         argv = ["pip", "install"] + self._commoninstallopts(indexserver)
+        # use pip-script on win32 to avoid the executable locking
+        if sys.platform == "win32":
+            argv[0] = "pip-script.py"
         if self.envconfig.downloadcache:
             self.envconfig.downloadcache.ensure(dir=1)
             argv.append("--download-cache=%s" %
@@ -251,16 +260,15 @@ class VirtualEnv(object):
                 ixserver = self.envconfig.config.indexserver['default']
             else:
                 ixserver = dep.indexserver
-            url = ixserver.url
-            d.setdefault(url, []).append(dep.name)
-            if url not in l:
-                l.append(url)
-            assert url is None or isinstance(url, str)
+            d.setdefault(ixserver, []).append(dep.name)
+            if ixserver not in l:
+                l.append(ixserver)
+            assert ixserver.url is None or isinstance(ixserver.url, str)
 
         extraopts = extraopts or []
-        for repo in l:
-            args = d[repo] + extraopts
-            self.pip_install(args, repo, action)
+        for ixserver in l:
+            args = d[ixserver] + extraopts
+            self.pip_install(args, ixserver.url, action)
 
     def _getenv(self):
         env = self.envconfig.setenv
@@ -274,22 +282,25 @@ class VirtualEnv(object):
     def test(self, redirect=False):
         action = self.session.newaction(self, "runtests")
         with action:
+            self.status = 0
             self.session.make_emptydir(self.envconfig.envtmpdir)
             cwd = self.envconfig.changedir
             for i, argv in enumerate(self.envconfig.commands):
-                action.setactivity("runtests", "commands[%s]" % i)
+                message = "commands[%s] | %s" % (i, ' '.join(argv))
+                action.setactivity("runtests", message)
                 try:
                     self._pcall(argv, cwd=cwd, action=action, redirect=redirect)
                 except tox.exception.InvocationError:
-                    self.session.report.error(str(sys.exc_info()[1]))
-                    return True
+                    val = sys.exc_info()[1]
+                    self.session.report.error(str(val))
+                    self.status = "commands failed"
+                except KeyboardInterrupt:
+                    self.status = "keyboardinterrupt"
+                    self.session.report.error(self.status)
+                    raise
 
     def _pcall(self, args, venv=True, cwd=None, extraenv={},
             action=None, redirect=True):
-        try:
-            del os.environ['PYTHONDONTWRITEBYTECODE']
-        except KeyError:
-            pass
         assert cwd
         cwd.ensure(dir=1)
         old = self.patchPATH()
@@ -318,22 +329,42 @@ if sys.platform != "win32":
         return py.path.local.sysfind(name)
 
 else:
+    # Exceptions to the usual windows mapping
     win32map = {
             'python': sys.executable,
-            'python2.4': "c:\python24\python.exe",
-            'python2.5': "c:\python25\python.exe",
-            'python2.6': "c:\python26\python.exe",
-            'python2.7': "c:\python27\python.exe",
-            'python3.1': "c:\python31\python.exe",
-            'python3.2': "c:\python32\python.exe",
             'jython': "c:\jython2.5.1\jython.bat",
     }
+    def locate_via_py(v_maj, v_min):
+        ver = "-%s.%s" % (v_maj, v_min)
+        script = "import sys; print(sys.executable)"
+        py_exe = py.path.local.sysfind('py')
+        if py_exe:
+            try:
+                exe = py_exe.sysexec(ver, '-c', script).strip()
+            except py.process.cmdexec.Error:
+                exe = None
+            if exe:
+                exe = py.path.local(exe)
+                if exe.check():
+                    return exe
+
     def find_executable(name):
-        p = py.path.local(name)
-        if p.check(file=1):
+        p = py.path.local.sysfind(name)
+        if p:
             return p
-        actual = win32map.get(name, None)
+        actual = None
+        # Is this a standard PythonX.Y name?
+        m = re.match(r"python(\d)\.(\d)", name)
+        if m:
+            # The standard names are in predictable places.
+            actual = r"c:\python%s%s\python.exe" % m.groups()
+        if not actual:
+            actual = win32map.get(name, None)
         if actual:
             actual = py.path.local(actual)
             if actual.check():
                 return actual
+        # The standard executables can be found as a last resort via the
+        # Python launcher py.exe
+        if m:
+            locate_via_py(*m.groups())
diff --git a/toxbootstrap.py b/toxbootstrap.py
index df53f45..37ddef5 100644
--- a/toxbootstrap.py
+++ b/toxbootstrap.py
@@ -58,7 +58,7 @@ ToDo
 
 """
 
-__version__ = '1.4.2'
+__version__ = '1.5.0'
 
 import sys
 import os
@@ -192,7 +192,7 @@ def cmdline(argv=None):
         # XXX: we use --no-site-packages because: if tox is installed in global
         # site-packages, then pip will not install it locally. ideal fix for
         # this should be to first look for tox in the global scripts/ directory
-        run('%s virtualenv.py --no-site-packages --distribute %s' %
+        run('%s virtualenv.py --no-site-packages --setuptools %s' %
                 (sys.executable, TENV))
         logging.info("removing virtualenv.py script after bootstrap venv creation")
         for x in ('', 'o', 'c'):
@@ -209,11 +209,6 @@ def cmdline(argv=None):
 
     # install/upgrade tox itself
     if USETOXDEV:
-        if 'PIP_DOWNLOAD_CACHE' in os.environ:
-            cache = ""
-        else:
-            cache = "--download-cache=_download"
-            ensuredir('_download')
         run('%s install -q -i http://pypi.testrun.org '
             '--upgrade %s tox' % (pip, cache))
     elif any([

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/tox.git



More information about the Python-modules-commits mailing list