summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorholger krekel <holger@merlinux.eu>2012-06-11 17:29:45 +0200
committerholger krekel <holger@merlinux.eu>2012-06-11 17:29:45 +0200
commit41ec030bf1b7923e4d239d8f8e9d7bcf8e9b60d1 (patch)
tree86e387c7f07110851d00dfa303c9d1ffb8ae037f
parentce346568ec38d23438c3b2f6c5dfbe6bffe6a365 (diff)
downloadtox-git-41ec030bf1b7923e4d239d8f8e9d7bcf8e9b60d1.tar.gz
streamline and somewhat simplify reporting, write release-announcement
-rw-r--r--doc/announce/release-1.4.txt41
-rw-r--r--tests/test_venv.py18
-rw-r--r--tests/test_z_cmdline.py11
-rw-r--r--tox.ini2
-rw-r--r--tox/_cmdline.py124
-rw-r--r--tox/_venv.py38
6 files changed, 152 insertions, 82 deletions
diff --git a/doc/announce/release-1.4.txt b/doc/announce/release-1.4.txt
new file mode 100644
index 00000000..f6a574e3
--- /dev/null
+++ b/doc/announce/release-1.4.txt
@@ -0,0 +1,41 @@
+tox 1.4: the virtualenv-based test run automatizer
+===========================================================================
+
+I am happy to announce tox 1.4 brings:
+
+- improvements with configuration file syntax, now allowing re-using
+ selected settings across config file sections. see
+
+- terminal reporting was simplified and streamlined. Now on
+ verbosity==0 (the default), less information will be shown
+ and you can use one or multiple "-v" options to increase verbosity.
+
+- internal re-organisation so that the separately released "detox"
+ tool can reuse tox code to implement a fully distributed tox run.
+
+More documentation:
+
+ http://tox.testrun.org/
+
+Installation:
+
+ pip install -U tox
+
+code hosting and issue tracking on bitbucket:
+
+ http://bitbucket.org/hpk42/tox
+
+What is tox?
+----------------
+
+tox standardizes and automates tedious 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
diff --git a/tests/test_venv.py b/tests/test_venv.py
index 877396bf..3db3a6b8 100644
--- a/tests/test_venv.py
+++ b/tests/test_venv.py
@@ -206,7 +206,7 @@ def test_install_sdist_indexserver(newmocksession, tmpdir):
venv = mocksession.getenv('python')
l = mocksession._pcalls
p = tmpdir.ensure("distfile.tar.gz")
- venv.install_sdist(str(p))
+ mocksession.installsdist(venv, p)
# two different index servers, two calls
assert len(l) == 1
args = " ".join(l[0].args)
@@ -219,10 +219,10 @@ def test_install_recreate(newmocksession):
""")
venv = mocksession.getenv('python')
venv.update()
- venv.install_sdist("xz")
- mocksession.report.expect("*", "*no existing*")
+ mocksession.installsdist(venv, "xz")
+ mocksession.report.expect("verbosity0", "*create*")
venv.update()
- mocksession.report.expect("*", "*configchange*detected*")
+ mocksession.report.expect("verbosity0", "*recreate*")
def test_install_error(newmocksession, monkeypatch):
mocksession = newmocksession(['--recreate'], """
@@ -354,7 +354,7 @@ class TestCreationConfig:
cconfig = venv._getliveconfig()
venv.update()
assert not venv.path_config.check()
- venv.install_sdist("sdist.zip")
+ mocksession.installsdist(venv, "sdist.zip")
assert venv.path_config.check()
assert mocksession._pcalls
args1 = map(str, mocksession._pcalls[0].args)
@@ -368,7 +368,7 @@ class TestCreationConfig:
cconfig.python = py.path.local("balla")
cconfig.writeconfig(venv.path_config)
venv.update()
- mocksession.report.expect("*", "configchange*")
+ mocksession.report.expect("verbosity0", "*recreate*")
def test_dep_recreation(self, newconfig, mocksession):
config = newconfig([], "")
@@ -439,7 +439,7 @@ def test_setenv_added_to_pcall(mocksession, newconfig):
venv = VirtualEnv(config.envconfigs['python'], session=mocksession)
# import pdb; pdb.set_trace()
- venv.install_sdist("xyz")
+ mocksession.installsdist(venv, "xyz")
venv.test()
l = mocksession._pcalls
@@ -459,7 +459,7 @@ def test_install_sdist_no_upgrade(newmocksession):
venv = mocksession.getenv('python')
venv.just_created = True
venv.envconfig.envdir.ensure(dir=1)
- venv.install_sdist("whatever")
+ mocksession.installsdist(venv, "whatever")
l = mocksession._pcalls
assert len(l) == 1
assert '-U' not in l[0].args
@@ -468,7 +468,7 @@ def test_install_sdist_upgrade(newmocksession):
mocksession = newmocksession([], "")
venv = mocksession.getenv('python')
assert not hasattr(venv, 'just_created')
- venv.install_sdist("whatever")
+ mocksession.installsdist(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 ee43586f..19eaa0b1 100644
--- a/tests/test_z_cmdline.py
+++ b/tests/test_z_cmdline.py
@@ -301,7 +301,7 @@ def test_test_simple(cmd, initproj):
changedir=tests
commands=
py.test --basetemp={envtmpdir} --junitxml=junit-{envname}.xml []
- deps=py
+ deps=pytest
'''
})
result = cmd.run("tox")
@@ -362,14 +362,13 @@ def test_notest(initproj, cmd):
result = cmd.run("tox", "-v", "--notest")
assert not result.ret
result.stdout.fnmatch_lines([
- "*test summary*",
+ "*summary*",
"*py25*skipped tests*",
])
result = cmd.run("tox", "-v", "--notest", "-epy25")
assert not result.ret
result.stdout.fnmatch_lines([
- "*py25*prepareenv*",
- "*reusing*",
+ "*py25*reusing*",
])
def test_env_PYTHONDONTWRITEBYTECODE(initproj, cmd, monkeypatch):
@@ -384,10 +383,10 @@ def test_env_PYTHONDONTWRITEBYTECODE(initproj, cmd, monkeypatch):
def test_sdistonly(initproj, cmd):
initproj("example123", filedefs={'tox.ini': """
"""})
- result = cmd.run("tox", "--sdistonly")
+ result = cmd.run("tox", "-v", "--sdistonly")
assert not result.ret
result.stdout.fnmatch_lines([
- "*using*setup.py*",
+ "*packaging sdist*setup.py*",
])
assert "virtualenv" not in result.stdout.str()
diff --git a/tox.ini b/tox.ini
index 4adc60cc..9abbaffe 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist=py27,py26,py25,py24,py31,py32,docs
+envlist=py27,py26,py25,py31,py32,docs
indexserver =
testrun = http://pypi.testrun.org
pypi = http://pypi.python.org/simple
diff --git a/tox/_cmdline.py b/tox/_cmdline.py
index 1d64c350..3557f577 100644
--- a/tox/_cmdline.py
+++ b/tox/_cmdline.py
@@ -4,11 +4,14 @@ Python2 and Python3 based virtual environments. Environments are
setup by using virtualenv. Configuration is generally done through an
INI-style "tox.ini" file.
"""
+from __future__ import with_statement
+
import tox
import py
import os
import sys
import subprocess
+import time
from tox._verlib import NormalizedVersion, IrrationalVersionError
from tox._venv import VirtualEnv
from tox._config import parseconfig
@@ -37,11 +40,21 @@ class Action(object):
else:
self.venvname = "GLOB"
+ def __enter__(self):
+ self.report.logaction_start(self)
+
+ def __exit__(self, *args):
+ self.report.logaction_finish(self)
+
def setactivity(self, name, msg):
self.activity = name
self.report.verbosity0("%s %s: %s" %(self.venvname, name, msg),
bold=True)
+ def info(self, name, msg):
+ self.report.verbosity1("%s %s: %s" %(self.venvname, name, msg),
+ bold=True)
+
def _initlogpath(self, actionid):
if self.venv:
logdir = self.venv.envconfig.envlogdir
@@ -76,14 +89,17 @@ class Action(object):
popen.cwd = cwd
popen.action = self
self._popenlist.append(popen)
- self.report.logpopen(popen)
try:
- out, err = popen.communicate()
- except KeyboardInterrupt:
- self.report.keyboard_interrupt()
- popen.wait()
- raise KeyboardInterrupt()
- ret = popen.wait()
+ self.report.logpopen(popen)
+ try:
+ out, err = popen.communicate()
+ except KeyboardInterrupt:
+ self.report.keyboard_interrupt()
+ popen.wait()
+ raise KeyboardInterrupt()
+ ret = popen.wait()
+ finally:
+ self._popenlist.remove(popen)
if ret:
invoked = " ".join(map(str, popen.args))
if outpath:
@@ -112,7 +128,7 @@ class Action(object):
return self.session.popen(args, shell=shell, cwd=str(cwd),
stdout=stdout, stderr=stderr, env=env)
-class Reporter:
+class Reporter(object):
actionchar = "-"
def __init__(self, session):
self.tw = py.io.TerminalWriter()
@@ -128,10 +144,18 @@ class Reporter:
else:
self.verbosity1(" %s$ %s " %(popen.cwd, cmd))
- def logaction(self, action):
- msg = action.msg
- msg += " " + " ".join(map(str, action.args))
- self.logline("%s %s" % (action.venvname, msg,), bold=True)
+ def logaction_start(self, action):
+ msg = action.msg + " " + " ".join(map(str, action.args))
+ self.verbosity1("%s start: %s" %(action.venvname, msg), bold=True)
+ self._starttime = time.time()
+
+ def logaction_finish(self, action):
+ duration = time.time() - self._starttime
+ self.verbosity1("%s finish: %s in %.2f seconds" %(
+ action.venvname, action.msg, duration), bold=True)
+
+ def startsummary(self):
+ self.tw.sep("_", "summary")
def info(self, msg):
if self.session.config.opts.verbosity >= 2:
@@ -178,6 +202,10 @@ class Reporter:
if self.session.config.opts.verbosity >= 1:
self.tw.line("%s" % msg, **opts)
+ def verbosity2(self, msg, **opts):
+ if self.session.config.opts.verbosity >= 2:
+ self.tw.line("%s" % msg, **opts)
+
#def log(self, msg):
# py.builtin.print_(msg, file=sys.stderr)
@@ -221,7 +249,6 @@ class Session:
def newaction(self, venv, msg, *args):
action = Action(self, venv, msg, args)
- self.report.logaction(action)
self._actions.append(action)
return action
@@ -256,16 +283,17 @@ class Session:
self.venvstatus[venv.path] = msg
def _makesdist(self):
- action = self.newaction(None, "prepare sdist package")
setup = self.config.setupdir.join("setup.py")
- action.setactivity("sdist-make", "using %s" % setup)
if not setup.check():
raise tox.exception.MissingFile(setup)
- self.make_emptydir(self.config.distdir)
- action.popen([sys.executable, setup, "sdist", "--formats=zip",
- "--dist-dir", self.config.distdir, ],
- cwd=self.config.setupdir)
- return self.config.distdir.listdir()[0]
+ action = self.newaction(None, "packaging")
+ with action:
+ action.setactivity("sdist-make", setup)
+ self.make_emptydir(self.config.distdir)
+ action.popen([sys.executable, setup, "sdist", "--formats=zip",
+ "--dist-dir", self.config.distdir, ],
+ cwd=self.config.setupdir)
+ return self.config.distdir.listdir()[0]
def make_emptydir(self, path):
if path.check():
@@ -273,29 +301,29 @@ class Session:
py.std.shutil.rmtree(str(path), ignore_errors=True)
path.ensure(dir=1)
- def setupenv(self, venv, sdist_path):
- action = self.newaction(venv, "prepareenv", venv.envconfig.envdir)
- if self._prepareenv(action, venv):
- if sdist_path is not None:
- self.installsdist(venv, sdist_path)
-
- def _prepareenv(self, action, venv):
- self.venvstatus[venv.path] = 0
- try:
- status = venv.update(action=action)
- except tox.exception.InvocationError:
- status = sys.exc_info()[1]
- if status:
- self.setenvstatus(venv, status)
- self.report.error(str(status))
- return False
- return True
+ def setupenv(self, venv):
+ action = self.newaction(venv, "getenv", venv.envconfig.envdir)
+ with action:
+ self.venvstatus[venv.path] = 0
+ try:
+ status = venv.update(action=action)
+ except tox.exception.InvocationError:
+ status = sys.exc_info()[1]
+ if status:
+ self.setenvstatus(venv, status)
+ self.report.error(str(status))
+ return False
+ return True
def installsdist(self, venv, sdist_path):
- try:
- venv.install_sdist(sdist_path)
- except tox.exception.InvocationError:
- self.setenvstatus(venv, sys.exc_info()[1])
+ action = self.newaction(venv, "sdist-install", sdist_path)
+ with action:
+ try:
+ venv.install_sdist(sdist_path, action)
+ return True
+ except tox.exception.InvocationError:
+ self.setenvstatus(venv, sys.exc_info()[1])
+ return False
def sdist(self):
if not self.config.opts.sdistonly and self.config.sdistsrc:
@@ -309,7 +337,7 @@ class Session:
except tox.exception.InvocationError:
v = sys.exc_info()[1]
self.report.error("FAIL could not package project")
- raise SystemExit(1)
+ return
sdistfile = self.config.distshare.join(sdist_path.basename)
if sdistfile != sdist_path:
self.report.info("copying new sdistfile to %r" %
@@ -320,26 +348,28 @@ class Session:
def subcommand_test(self):
sdist_path = self.sdist()
+ if not sdist_path:
+ return 2
if self.config.opts.sdistonly:
return
for venv in self.venvlist:
- self.setupenv(venv, sdist_path)
- self.runtestenv(venv, sdist_path)
+ if self.setupenv(venv):
+ self.installsdist(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.opts.notest:
- testaction = self.newaction(venv, "runtests")
if self.venvstatus[venv.path]:
return
- if venv.test(testaction, redirect=redirect):
+ if venv.test(redirect=redirect):
self.setenvstatus(venv, "commands failed")
else:
self.setenvstatus(venv, "skipped tests")
def _summary(self):
- action = self.newaction(None, "test summary")
+ self.report.startsummary()
retcode = 0
for venv in self.venvlist:
status = self.venvstatus[venv.path]
diff --git a/tox/_venv.py b/tox/_venv.py
index 99986e01..0a253f27 100644
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -1,4 +1,4 @@
-
+from __future__ import with_statement
import sys, os
import py
import tox
@@ -103,13 +103,12 @@ class VirtualEnv(object):
rconfig = CreationConfig.readconfig(self.path_config)
if not self.envconfig.recreate and rconfig and \
rconfig.matches(self._getliveconfig()):
- action.setactivity("reusing", "existing environment matches")
+ action.info("reusing", self.envconfig.envdir)
return
if rconfig is None:
- action.setactivity("create", "no existing environment found")
+ action.setactivity("create", self.envconfig.envdir)
else:
- action.setactivity("recreate",
- "configchange/incomplete install detected")
+ action.setactivity("recreate", self.envconfig.envdir)
try:
self.create(action)
except tox.exception.UnsupportedInterpreter:
@@ -192,13 +191,14 @@ class VirtualEnv(object):
self._pcall(args, venv=False, action=action, cwd=basepath)
self.just_created = True
- def install_sdist(self, sdistpath):
+ def install_sdist(self, sdistpath, action):
+ assert action is not None
if getattr(self, 'just_created', False):
- action = self.session.newaction(self, "sdist-inst", sdistpath)
+ action.setactivity("sdist-inst", sdistpath)
self._getliveconfig().writeconfig(self.path_config)
extraopts = []
else:
- action = self.session.newaction(self, "sdist-reinst", sdistpath)
+ action.setactivity("sdist-reinst", sdistpath)
extraopts = ['-U', '--no-deps']
self._install([sdistpath], extraopts=extraopts, action=action)
@@ -271,17 +271,17 @@ class VirtualEnv(object):
env_arg = None
return env_arg
- def test(self, action=None, redirect=False):
- if action is None:
- action = self.session.newaction(self, "test")
- self.session.make_emptydir(self.envconfig.envtmpdir)
- cwd = self.envconfig.changedir
- for argv in self.envconfig.commands:
- 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
+ def test(self, redirect=False):
+ action = self.session.newaction(self, "runtests")
+ with action:
+ self.session.make_emptydir(self.envconfig.envtmpdir)
+ cwd = self.envconfig.changedir
+ for argv in self.envconfig.commands:
+ 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
def _pcall(self, args, venv=True, cwd=None, extraenv={},
action=None, redirect=True):