diff options
Diffstat (limited to 'tox')
-rw-r--r-- | tox/__init__.py | 8 | ||||
-rw-r--r-- | tox/_pytestplugin.py | 9 | ||||
-rw-r--r-- | tox/_quickstart.py | 2 | ||||
-rw-r--r-- | tox/config.py | 50 | ||||
-rw-r--r-- | tox/interpreters.py | 6 | ||||
-rw-r--r-- | tox/result.py | 6 | ||||
-rw-r--r-- | tox/session.py | 34 |
7 files changed, 81 insertions, 34 deletions
diff --git a/tox/__init__.py b/tox/__init__.py index c17341d..baf651b 100644 --- a/tox/__init__.py +++ b/tox/__init__.py @@ -1,5 +1,5 @@ # -__version__ = '2.3.2' +__version__ = '2.4.0.dev1' from .hookspecs import hookspec, hookimpl # noqa @@ -23,5 +23,11 @@ class exception: """ a directory did not exist. """ class MissingDependency(Error): """ a dependency could not be found or determined. """ + class MinVersionError(Error): + """ the installed tox version is lower than requested minversion. """ + + def __init__(self, message): + self.message = message + super(exception.MinVersionError, self).__init__(message) from tox.session import main as cmdline # noqa diff --git a/tox/_pytestplugin.py b/tox/_pytestplugin.py index f15d2ec..785070d 100644 --- a/tox/_pytestplugin.py +++ b/tox/_pytestplugin.py @@ -68,12 +68,12 @@ class ReportExpectMock: def generic_report(*args, **kwargs): self._calls.append((name,) + args) - print ("%s" % (self._calls[-1], )) + 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], )) + print("%s" % (self._calls[-1], )) return Action(self.session, venv, msg, args) def getnext(self, cat): @@ -195,6 +195,9 @@ class Cmd: return py.std.subprocess.Popen(argv, stdout=stdout, stderr=stderr, **kw) def run(self, *argv): + if argv[0] == "tox" and sys.version_info[:2] < (2, 7): + pytest.skip("can not run tests involving calling tox on python2.6. " + "(and python2.6 is about to be deprecated anyway)") argv = [str(x) for x in argv] assert py.path.local.sysfind(str(argv[0])), argv[0] p1 = self.tmpdir.join("stdout") @@ -316,7 +319,7 @@ def initproj(request, tmpdir): 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,)) + print("created project in %s" % (base,)) base.chdir() return initproj diff --git a/tox/_quickstart.py b/tox/_quickstart.py index a397cb1..59ee48e 100644 --- a/tox/_quickstart.py +++ b/tox/_quickstart.py @@ -119,7 +119,7 @@ def do_prompt(d, key, text, default=None, validator=nonempty): x = term_input(prompt) if default and not x: x = default - if sys.version_info < (3, ) and not isinstance(x, unicode): + if sys.version_info < (3, ) and not isinstance(x, unicode): # noqa # 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: diff --git a/tox/config.py b/tox/config.py index 974bbbb..99e678d 100644 --- a/tox/config.py +++ b/tox/config.py @@ -12,6 +12,7 @@ import pluggy import tox.interpreters from tox import hookspecs +from tox._verlib import NormalizedVersion import py @@ -181,7 +182,7 @@ class PosargsOption: class InstallcmdOption: name = "install_command" type = "argv" - default = "pip install {opts} {packages}" + default = "python -m pip install {opts} {packages}" help = "install command for dependencies and package under test." def postprocess(self, testenv_config, value): @@ -225,7 +226,10 @@ def parseconfig(args=None, plugins=()): if inipath.check(): break else: - feedback("toxini file %r not found" % (basename), sysexit=True) + inipath = py.path.local().join('setup.cfg') + if not inipath.check(): + feedback("toxini file %r not found" % (basename), sysexit=True) + try: parseini(config, inipath) except tox.exception.InterpreterNotFound: @@ -367,6 +371,9 @@ def tox_addoption(parser): help="override sitepackages setting to True in all envs") parser.add_argument("--skip-missing-interpreters", action="store_true", help="don't fail tests for missing interpreters") + parser.add_argument("--workdir", action="store", + dest="workdir", metavar="PATH", default=None, + help="tox working directory") parser.add_argument("args", nargs="*", help="additional arguments available to command positional substitution") @@ -518,6 +525,13 @@ def tox_addoption(parser): help="install package in develop/editable mode") parser.add_testenv_attribute_obj(InstallcmdOption()) + + parser.add_testenv_attribute( + name="list_dependencies_command", + type="argv", + default="python -m pip freeze", + help="list dependencies for a virtual environment") + parser.add_testenv_attribute_obj(DepOption()) parser.add_testenv_attribute( @@ -645,12 +659,18 @@ class parseini: self._cfg = py.iniconfig.IniConfig(config.toxinipath) config._cfg = self._cfg self.config = config + + if inipath.basename == 'setup.cfg': + prefix = 'tox' + else: + prefix = None ctxname = getcontextname() if ctxname == "jenkins": - reader = SectionReader("tox:jenkins", self._cfg, fallbacksections=['tox']) + reader = SectionReader("tox:jenkins", self._cfg, prefix=prefix, + fallbacksections=['tox']) distshare_default = "{toxworkdir}/distshare" elif not ctxname: - reader = SectionReader("tox", self._cfg) + reader = SectionReader("tox", self._cfg, prefix=prefix) distshare_default = "{homedir}/.tox/distshare" else: raise ValueError("invalid context") @@ -665,8 +685,20 @@ class parseini: reader.addsubstitutions(toxinidir=config.toxinidir, homedir=config.homedir) - config.toxworkdir = reader.getpath("toxworkdir", "{toxinidir}/.tox") + # As older versions of tox may have bugs or incompatabilities that + # prevent parsing of tox.ini this must be the first thing checked. config.minversion = reader.getstring("minversion", None) + if config.minversion: + minversion = NormalizedVersion(self.config.minversion) + toxversion = NormalizedVersion(tox.__version__) + if toxversion < minversion: + raise tox.exception.MinVersionError( + "tox version is %s, required is at least %s" % ( + toxversion, minversion)) + if config.option.workdir is None: + config.toxworkdir = reader.getpath("toxworkdir", "{toxinidir}/.tox") + else: + config.toxworkdir = config.toxinidir.join(config.option.workdir, abs=True) if not config.option.skip_missing_interpreters: config.option.skip_missing_interpreters = \ @@ -854,8 +886,12 @@ is_section_substitution = re.compile("{\[[^{}\s]+\]\S+?}").match class SectionReader: - def __init__(self, section_name, cfgparser, fallbacksections=None, factors=()): - self.section_name = section_name + def __init__(self, section_name, cfgparser, fallbacksections=None, + factors=(), prefix=None): + if prefix is None: + self.section_name = section_name + else: + self.section_name = "%s:%s" % (prefix, section_name) self._cfg = cfgparser self.fallbacksections = fallbacksections or [] self.factors = factors diff --git a/tox/interpreters.py b/tox/interpreters.py index 66e6409..e049f1d 100644 --- a/tox/interpreters.py +++ b/tox/interpreters.py @@ -43,10 +43,10 @@ class Interpreters: try: res = exec_on_interpreter(info.executable, [inspect.getsource(sitepackagesdir), - "print (sitepackagesdir(%r))" % envdir]) + "print(sitepackagesdir(%r))" % envdir]) except ExecFailed: val = sys.exc_info()[1] - print ("execution failed: %s -- %s" % (val.out, val.err)) + print("execution failed: %s -- %s" % (val.out, val.err)) return "" else: return res["dir"] @@ -56,7 +56,7 @@ def run_and_get_interpreter_info(name, executable): assert executable try: result = exec_on_interpreter(executable, - [inspect.getsource(pyinfo), "print (pyinfo())"]) + [inspect.getsource(pyinfo), "print(pyinfo())"]) except ExecFailed: val = sys.exc_info()[1] return NoInterpreterInfo(name, executable=val.executable, diff --git a/tox/result.py b/tox/result.py index 96ac612..bad8cc3 100644 --- a/tox/result.py +++ b/tox/result.py @@ -47,9 +47,9 @@ class EnvLog: pythonexecutable = py.path.local(pythonexecutable) out = pythonexecutable.sysexec("-c", "import sys; " - "print (sys.executable);" - "print (list(sys.version_info)); " - "print (sys.version)") + "print(sys.executable);" + "print(list(sys.version_info)); " + "print(sys.version)") lines = out.splitlines() executable = lines.pop(0) version_info = eval(lines.pop(0)) diff --git a/tox/session.py b/tox/session.py index 1c9bbef..e29696e 100644 --- a/tox/session.py +++ b/tox/session.py @@ -15,7 +15,6 @@ from tox._verlib import NormalizedVersion, IrrationalVersionError from tox.venv import VirtualEnv from tox.config import parseconfig from tox.result import ResultLog -from tox.hookspecs import hookimpl from subprocess import STDOUT @@ -41,6 +40,10 @@ def main(args=None): raise SystemExit(retcode) except KeyboardInterrupt: raise SystemExit(2) + except tox.exception.MinVersionError as e: + r = Reporter(None) + r.error(e.message) + raise SystemExit(1) def show_help(config): @@ -234,6 +237,12 @@ class Reporter(object): self._reportedlines = [] # self.cumulated_time = 0.0 + def _get_verbosity(self): + if self.session: + return self.session.config.option.verbosity + else: + return 2 + def logpopen(self, popen, env): """ log information about the action.popen() created process. """ cmd = " ".join(map(str, popen.args)) @@ -253,16 +262,17 @@ class Reporter(object): # self.cumulated_time += duration self.verbosity2("%s finish: %s after %.2f seconds" % ( action.venvname, action.msg, duration), bold=True) + delattr(action, '_starttime') def startsummary(self): self.tw.sep("_", "summary") def info(self, msg): - if self.session.config.option.verbosity >= 2: + if self._get_verbosity() >= 2: self.logline(msg) def using(self, msg): - if self.session.config.option.verbosity >= 1: + if self._get_verbosity() >= 1: self.logline("using %s" % (msg,), bold=True) def keyboard_interrupt(self): @@ -298,15 +308,15 @@ class Reporter(object): self.tw.line("%s" % msg, **opts) def verbosity0(self, msg, **opts): - if self.session.config.option.verbosity >= 0: + if self._get_verbosity() >= 0: self.logline("%s" % msg, **opts) def verbosity1(self, msg, **opts): - if self.session.config.option.verbosity >= 1: + if self._get_verbosity() >= 1: self.logline("%s" % msg, **opts) def verbosity2(self, msg, **opts): - if self.session.config.option.verbosity >= 2: + if self._get_verbosity() >= 2: self.logline("%s" % msg, **opts) # def log(self, msg): @@ -364,14 +374,6 @@ class Session: def runcommand(self): self.report.using("tox-%s from %s" % (tox.__version__, tox.__file__)) - if self.config.minversion: - minversion = NormalizedVersion(self.config.minversion) - toxversion = NormalizedVersion(tox.__version__) - if toxversion < minversion: - self.report.error( - "tox version is %s, required is at least %s" % ( - toxversion, minversion)) - raise SystemExit(1) if self.config.option.showconfig: self.showconfig() elif self.config.option.listenvs: @@ -539,8 +541,8 @@ class Session: # write out version dependency information action = self.newaction(venv, "envreport") with action: - pip = venv.getcommandpath("pip") - output = venv._pcall([str(pip), "freeze"], + args = venv.envconfig.list_dependencies_command + output = venv._pcall(args, cwd=self.config.toxinidir, action=action) # the output contains a mime-header, skip it |