diff options
author | holger krekel <holger@merlinux.eu> | 2012-06-11 17:29:45 +0200 |
---|---|---|
committer | holger krekel <holger@merlinux.eu> | 2012-06-11 17:29:45 +0200 |
commit | 41ec030bf1b7923e4d239d8f8e9d7bcf8e9b60d1 (patch) | |
tree | 86e387c7f07110851d00dfa303c9d1ffb8ae037f | |
parent | ce346568ec38d23438c3b2f6c5dfbe6bffe6a365 (diff) | |
download | tox-git-41ec030bf1b7923e4d239d8f8e9d7bcf8e9b60d1.tar.gz |
streamline and somewhat simplify reporting, write release-announcement
-rw-r--r-- | doc/announce/release-1.4.txt | 41 | ||||
-rw-r--r-- | tests/test_venv.py | 18 | ||||
-rw-r--r-- | tests/test_z_cmdline.py | 11 | ||||
-rw-r--r-- | tox.ini | 2 | ||||
-rw-r--r-- | tox/_cmdline.py | 124 | ||||
-rw-r--r-- | tox/_venv.py | 38 |
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() @@ -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): |