summaryrefslogtreecommitdiff
path: root/tox
diff options
context:
space:
mode:
authorVladimir Vitvitskiy <vladimir.vitvitskiy@hp.com>2015-04-23 00:18:46 +0300
committerVladimir Vitvitskiy <vladimir.vitvitskiy@hp.com>2015-04-23 00:18:46 +0300
commitad220729fd9c08662f2fbc5beda265ddaffe62a0 (patch)
tree76ad86167ce78fdeaf9eaed20d2646218332626c /tox
parentaccadc9fadca83bd9fbe4bc06884d268ff8f9618 (diff)
downloadtox-ad220729fd9c08662f2fbc5beda265ddaffe62a0.tar.gz
fix PEP8 violations
* tox.ini updated to run PEP8 checks along with flakes * added dev test environment to run any command in it or looponfail tests * fixed all PEP8 violations pytest-pep8 complained about * line width set to 99
Diffstat (limited to 'tox')
-rw-r--r--tox/__init__.py4
-rw-r--r--tox/_cmdline.py94
-rw-r--r--tox/_config.py175
-rw-r--r--tox/_exception.py14
-rw-r--r--tox/_pytestplugin.py64
-rw-r--r--tox/_quickstart.py17
-rw-r--r--tox/_venv.py57
-rw-r--r--tox/_verlib.py16
-rw-r--r--tox/interpreters.py24
-rw-r--r--tox/result.py13
10 files changed, 278 insertions, 200 deletions
diff --git a/tox/__init__.py b/tox/__init__.py
index 95f2dfb..7869fcb 100644
--- a/tox/__init__.py
+++ b/tox/__init__.py
@@ -1,10 +1,12 @@
#
__version__ = '2.0.0.dev1'
+
class exception:
class Error(Exception):
def __str__(self):
- return "%s: %s" %(self.__class__.__name__, self.args[0])
+ return "%s: %s" % (self.__class__.__name__, self.args[0])
+
class ConfigError(Error):
""" error in tox configuration. """
class UnsupportedInterpreter(Error):
diff --git a/tox/_cmdline.py b/tox/_cmdline.py
index 5846c7c..0236d17 100644
--- a/tox/_cmdline.py
+++ b/tox/_cmdline.py
@@ -17,9 +17,11 @@ from tox._config import parseconfig
from tox.result import ResultLog
from subprocess import STDOUT
+
def now():
return py.std.time.time()
+
def main(args=None):
try:
config = parseconfig(args, 'tox')
@@ -28,6 +30,7 @@ def main(args=None):
except KeyboardInterrupt:
raise SystemExit(2)
+
class Action(object):
def __init__(self, session, venv, msg, args):
self.venv = venv
@@ -55,12 +58,10 @@ class Action(object):
def setactivity(self, name, msg):
self.activity = name
- self.report.verbosity0("%s %s: %s" %(self.venvname, name, msg),
- bold=True)
+ 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)
+ self.report.verbosity1("%s %s: %s" % (self.venvname, name, msg), bold=True)
def _initlogpath(self, actionid):
if self.venv:
@@ -83,8 +84,8 @@ class Action(object):
resultjson = self.session.config.option.resultjson
if resultjson or redirect:
fout = self._initlogpath(self.id)
- fout.write("actionid=%s\nmsg=%s\ncmdargs=%r\nenv=%s\n" %(
- self.id, self.msg, args, env))
+ fout.write("actionid=%s\nmsg=%s\ncmdargs=%r\nenv=%s\n" % (
+ self.id, self.msg, args, env))
fout.flush()
self.popen_outpath = outpath = py.path.local(fout.name)
fin = outpath.open()
@@ -154,9 +155,9 @@ class Action(object):
if hasattr(self, "commandlog"):
self.commandlog.add_command(popen.args, out, ret)
raise tox.exception.InvocationError(
- "%s (see %s)" %(invoked, outpath), ret)
+ "%s (see %s)" % (invoked, outpath), ret)
else:
- raise tox.exception.InvocationError("%r" %(invoked, ))
+ raise tox.exception.InvocationError("%r" % (invoked, ))
if not out and outpath:
out = outpath.read()
if hasattr(self, "commandlog"):
@@ -170,8 +171,8 @@ class Action(object):
arg = cwd.bestrelpath(arg)
newargs.append(str(arg))
- #subprocess does not always take kindly to .py scripts
- #so adding the interpreter here.
+ # 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:
@@ -184,39 +185,37 @@ class Action(object):
if env is None:
env = os.environ.copy()
return self.session.popen(args, shell=False, cwd=str(cwd),
- universal_newlines=True,
- stdout=stdout, stderr=stderr, env=env)
-
+ universal_newlines=True,
+ 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
+ # self.cumulated_time = 0.0
def logpopen(self, popen, env):
""" log information about the action.popen() created process. """
cmd = " ".join(map(str, popen.args))
if popen.outpath:
- self.verbosity1(" %s$ %s >%s" %(popen.cwd, cmd,
- popen.outpath,
- ))
+ self.verbosity1(" %s$ %s >%s" % (popen.cwd, cmd, popen.outpath,))
else:
- self.verbosity1(" %s$ %s " %(popen.cwd, cmd))
+ self.verbosity1(" %s$ %s " % (popen.cwd, cmd))
def logaction_start(self, action):
msg = action.msg + " " + " ".join(map(str, action.args))
- self.verbosity2("%s start: %s" %(action.venvname, msg), bold=True)
+ self.verbosity2("%s start: %s" % (action.venvname, msg), bold=True)
assert not hasattr(action, "_starttime")
action._starttime = now()
def logaction_finish(self, action):
duration = now() - action._starttime
- #self.cumulated_time += duration
- self.verbosity2("%s finish: %s after %.2f seconds" %(
+ # self.cumulated_time += duration
+ self.verbosity2("%s finish: %s after %.2f seconds" % (
action.venvname, action.msg, duration), bold=True)
def startsummary(self):
@@ -228,8 +227,7 @@ class Reporter(object):
def using(self, msg):
if self.session.config.option.verbosity >= 1:
- self.logline("using %s" %(msg,), bold=True)
-
+ self.logline("using %s" % (msg,), bold=True)
def keyboard_interrupt(self):
self.error("KEYBOARDINTERRUPT")
@@ -275,7 +273,7 @@ class Reporter(object):
if self.session.config.option.verbosity >= 2:
self.logline("%s" % msg, **opts)
- #def log(self, msg):
+ # def log(self, msg):
# py.builtin.print_(msg, file=sys.stderr)
@@ -288,13 +286,15 @@ class Session:
self.report = Report(self)
self.make_emptydir(config.logdir)
config.logdir.ensure(dir=1)
- #self.report.using("logdir %s" %(self.config.logdir,))
- self.report.using("tox.ini: %s" %(self.config.toxinipath,))
+ # self.report.using("logdir %s" %(self.config.logdir,))
+ self.report.using("tox.ini: %s" % (self.config.toxinipath,))
self._spec2pkg = {}
self._name2venv = {}
try:
- self.venvlist = [self.getvenv(x)
- for x in self.config.envlist]
+ self.venvlist = [
+ self.getvenv(x)
+ for x in self.config.envlist
+ ]
except LookupError:
raise SystemExit(1)
self._actions = []
@@ -321,15 +321,14 @@ class Session:
return action
def runcommand(self):
- 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__)
if toxversion < minversion:
self.report.error(
- "tox version is %s, required is at least %s" %(
- toxversion, minversion))
+ "tox version is %s, required is at least %s" % (
+ toxversion, minversion))
raise SystemExit(1)
if self.config.option.showconfig:
self.showconfig()
@@ -342,7 +341,7 @@ class Session:
for relpath in pathlist:
src = srcdir.join(relpath)
if not src.check():
- self.report.error("missing source file: %s" %(src,))
+ self.report.error("missing source file: %s" % (src,))
raise SystemExit(1)
target = destdir.join(relpath)
target.dirpath().ensure(dir=1)
@@ -358,7 +357,7 @@ class Session:
self.make_emptydir(self.config.distdir)
action.popen([sys.executable, setup, "sdist", "--formats=zip",
"--dist-dir", self.config.distdir, ],
- cwd=self.config.setupdir)
+ cwd=self.config.setupdir)
try:
return self.config.distdir.listdir()[0]
except py.error.ENOENT:
@@ -375,12 +374,11 @@ class Session:
)
raise SystemExit(1)
self.report.error(
- 'No dist directory found. Please check setup.py, e.g with:\n'\
+ 'No dist directory found. Please check setup.py, e.g with:\n'
' python setup.py sdist'
- )
+ )
raise SystemExit(1)
-
def make_emptydir(self, path):
if path.check():
self.report.info(" removing %s" % path)
@@ -446,25 +444,25 @@ class Session:
:rtype: py.path.local
"""
if not self.config.option.sdistonly and (self.config.sdistsrc or
- self.config.option.installpkg):
+ 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))
+ str(sdist_path))
else:
try:
sdist_path = self._makesdist()
except tox.exception.InvocationError:
v = sys.exc_info()[1]
self.report.error("FAIL could not package project - v = %r" %
- v)
+ v)
return
sdistfile = self.config.distshare.join(sdist_path.basename)
if sdistfile != sdist_path:
self.report.info("copying new sdistfile to %r" %
- str(sdistfile))
+ str(sdistfile))
try:
sdistfile.dirpath().ensure(dir=1)
except py.error.Error:
@@ -513,24 +511,23 @@ class Session:
for venv in self.venvlist:
status = venv.status
if isinstance(status, tox.exception.InterpreterNotFound):
- msg = " %s: %s" %(venv.envconfig.envname, str(status))
+ msg = " %s: %s" % (venv.envconfig.envname, str(status))
if self.config.option.skip_missing_interpreters:
self.report.skip(msg)
else:
retcode = 1
self.report.error(msg)
elif status == "platform mismatch":
- msg = " %s: %s" %(venv.envconfig.envname, str(status))
+ msg = " %s: %s" % (venv.envconfig.envname, str(status))
self.report.verbosity1(msg)
elif status and status != "skipped tests":
- msg = " %s: %s" %(venv.envconfig.envname, str(status))
+ msg = " %s: %s" % (venv.envconfig.envname, str(status))
self.report.error(msg)
retcode = 1
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 :)")
@@ -586,7 +583,6 @@ class Session:
versions.append("virtualenv-%s" % version.strip())
self.report.keyvalue("tool-versions:", " ".join(versions))
-
def _resolve_pkg(self, pkgspec):
try:
return self._spec2pkg[pkgspec]
@@ -614,7 +610,7 @@ class Session:
items.append((ver, x))
else:
self.report.warning("could not determine version of: %s" %
- str(x))
+ str(x))
items.sort()
if not items:
raise tox.exception.MissingDependency(pkgspec)
@@ -624,6 +620,8 @@ class Session:
_rex_getversion = py.std.re.compile("[\w_\-\+\.]+-(.*)(\.zip|\.tar.gz)")
+
+
def getversion(basename):
m = _rex_getversion.match(basename)
if m is None:
diff --git a/tox/_config.py b/tox/_config.py
index 9d054a0..afd2c55 100644
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -45,7 +45,7 @@ def parseconfig(args=None, pkg=None):
if inipath.check():
break
else:
- feedback("toxini file %r not found" %(basename), sysexit=True)
+ feedback("toxini file %r not found" % (basename), sysexit=True)
try:
parseini(config, inipath)
except tox.exception.InterpreterNotFound:
@@ -54,98 +54,104 @@ def parseconfig(args=None, pkg=None):
py.builtin.print_("ERROR: " + str(exn))
return config
+
def feedback(msg, sysexit=False):
py.builtin.print_("ERROR: " + msg, file=sys.stderr)
if sysexit:
raise SystemExit(1)
+
class VersionAction(argparse.Action):
def __call__(self, argparser, *args, **kwargs):
name = argparser.pkgname
mod = __import__(name)
version = mod.__version__
- py.builtin.print_("%s imported from %s" %(version, mod.__file__))
+ py.builtin.print_("%s imported from %s" % (version, mod.__file__))
raise SystemExit(0)
+
class CountAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if hasattr(namespace, self.dest):
- setattr(namespace, self.dest, int(getattr(namespace, self.dest))+1)
+ setattr(namespace, self.dest, int(getattr(namespace, self.dest)) + 1)
else:
setattr(namespace, self.dest, 0)
+
def prepare_parse(pkgname):
parser = argparse.ArgumentParser(description=__doc__,)
- #formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ # formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.pkgname = pkgname
parser.add_argument("--version", nargs=0, action=VersionAction,
- dest="version",
- help="report version information to stdout.")
+ dest="version",
+ help="report version information to stdout.")
parser.add_argument("-v", nargs=0, action=CountAction, default=0,
- dest="verbosity",
- help="increase verbosity of reporting output.")
+ dest="verbosity",
+ help="increase verbosity of reporting output.")
parser.add_argument("--showconfig", action="store_true",
- help="show configuration information for all environments. ")
+ help="show configuration information for all environments. ")
parser.add_argument("-l", "--listenvs", action="store_true",
- dest="listenvs", help="show list of test environments")
+ 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 name.")
+ dest="configfile",
+ help="use the specified config file name.")
parser.add_argument("-e", action="append", dest="env",
- metavar="envlist",
- help="work against specified environments (ALL selects all).")
+ metavar="envlist",
+ help="work against specified environments (ALL selects all).")
parser.add_argument("--notest", action="store_true", dest="notest",
- help="skip invoking test commands.")
+ help="skip invoking test commands.")
parser.add_argument("--sdistonly", action="store_true", dest="sdistonly",
- help="only perform the sdist packaging activity.")
+ help="only perform the sdist packaging activity.")
parser.add_argument("--installpkg", action="store", default=None,
- metavar="PATH",
- help="use specified package for installation into venv, instead of "
- "creating an sdist.")
+ metavar="PATH",
+ help="use specified package for installation into venv, instead of "
+ "creating an sdist.")
parser.add_argument("--develop", action="store_true", dest="develop",
- help="install package in the venv using 'setup.py develop' via "
- "'pip -e .'")
+ help="install package in the venv using 'setup.py develop' via "
+ "'pip -e .'")
parser.add_argument("--set-home", action="store_true", dest="sethome",
- help="(experimental) force creating a new $HOME for each test "
- "environment and create .pydistutils.cfg|pip.conf files "
- "if index servers are specified with tox. ")
+ help="(experimental) force creating a new $HOME for each test "
+ "environment and create .pydistutils.cfg|pip.conf files "
+ "if index servers are specified with tox. ")
parser.add_argument('-i', action="append",
- dest="indexurl", metavar="URL",
- help="set indexserver url (if URL is of form name=url set the "
- "url for the 'name' indexserver, specifically)")
+ dest="indexurl", metavar="URL",
+ help="set indexserver url (if URL is of form name=url set the "
+ "url for the 'name' indexserver, specifically)")
parser.add_argument("--pre", action="store_true", dest="pre",
- help="install pre-releases and development versions of dependencies. "
- "This will pass the --pre option to install_command (pip by default).")
+ help="install pre-releases and development versions of dependencies. "
+ "This will pass the --pre option to install_command "
+ "(pip by default).")
parser.add_argument("-r", "--recreate", action="store_true",
- dest="recreate",
- help="force recreation of virtual environments")
+ dest="recreate",
+ help="force recreation of virtual environments")
parser.add_argument("--result-json", action="store",
- dest="resultjson", metavar="PATH",
- help="write a json file with detailed information about "
- "all commands and results involved. This will turn off "
- "pass-through output from running test commands which is "
- "instead captured into the json result file.")
+ dest="resultjson", metavar="PATH",
+ help="write a json file with detailed information about "
+ "all commands and results involved. This will turn off "
+ "pass-through output from running test commands which is "
+ "instead captured into the json result file.")
# We choose 1 to 4294967295 because it is the range of PYTHONHASHSEED.
parser.add_argument("--hashseed", action="store",
- metavar="SEED", default=None,
- help="set PYTHONHASHSEED to SEED before running commands. "
- "Defaults to a random integer in the range [1, 4294967295] "
- "([1, 1024] on Windows). "
- "Passing 'noset' suppresses this behavior.")
+ metavar="SEED", default=None,
+ help="set PYTHONHASHSEED to SEED before running commands. "
+ "Defaults to a random integer in the range [1, 4294967295] "
+ "([1, 1024] on Windows). "
+ "Passing 'noset' suppresses this behavior.")
parser.add_argument("--force-dep", action="append",
- metavar="REQ", default=None,
- help="Forces a certain version of one of the dependencies "
- "when configuring the virtual environment. REQ Examples "
- "'pytest<2.7' or 'django>=1.6'.")
+ metavar="REQ", default=None,
+ help="Forces a certain version of one of the dependencies "
+ "when configuring the virtual environment. REQ Examples "
+ "'pytest<2.7' or 'django>=1.6'.")
parser.add_argument("--sitepackages", action="store_true",
- help="override sitepackages setting to True in all envs")
+ 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")
+ help="don't fail tests for missing interpreters")
parser.add_argument("args", nargs="*",
- help="additional arguments available to command positional substitution")
+ help="additional arguments available to command positional substitution")
return parser
+
class Config(object):
def __init__(self):
self.envconfigs = {}
@@ -167,8 +173,9 @@ class VenvConfig:
@property
def envbindir(self):
- if (sys.platform == "win32" and "jython" not in self.basepython
- and "pypy" 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")
@@ -185,8 +192,8 @@ class VenvConfig:
def envsitepackagesdir(self):
self.getsupportedinterpreter() # for throwing exceptions
x = self.config.interpreters.get_sitepackagesdir(
- info=self._basepython_info,
- envdir=self.envdir)
+ info=self._basepython_info,
+ envdir=self.envdir)
return x
def getsupportedinterpreter(self):
@@ -200,27 +207,29 @@ class VenvConfig:
if not info.version_info:
raise tox.exception.InvocationError(
'Failed to get version_info for %s: %s' % (info.name, info.err))
- if info.version_info < (2,6):
+ if info.version_info < (2, 6):
raise tox.exception.UnsupportedInterpreter(
"python2.5 is not supported anymore, sorry")
return info.executable
-
testenvprefix = "testenv:"
+
def get_homedir():
try:
return py.path.local._gethomedir()
except Exception:
return None
+
def make_hashseed():
max_seed = 4294967295
if sys.platform == 'win32':
max_seed = 1024
return str(random.randint(1, max_seed))
+
class parseini:
def __init__(self, config, inipath):
config.toxinipath = inipath
@@ -287,8 +296,7 @@ class parseini:
config.indexserver[name] = IndexServerConfig(name, override)
reader.addsubstitutions(toxworkdir=config.toxworkdir)
- config.distdir = reader.getpath(toxsection, "distdir",
- "{toxworkdir}/dist")
+ config.distdir = reader.getpath(toxsection, "distdir", "{toxworkdir}/dist")
reader.addsubstitutions(distdir=config.distdir)
config.distshare = reader.getpath(toxsection, "distshare",
distshare_default)
@@ -335,18 +343,18 @@ class parseini:
def _makeenvconfig(self, name, section, subs, config):
vc = VenvConfig(config=config, envname=name)
factors = set(name.split('-'))
- reader = IniReader(self._cfg, fallbacksections=["testenv"],
- factors=factors)
+ reader = IniReader(self._cfg, fallbacksections=["testenv"], factors=factors)
reader.addsubstitutions(**subs)
- vc.develop = not config.option.installpkg and \
- reader.getbool(section, "usedevelop", config.option.develop)
+ vc.develop = (
+ not config.option.installpkg
+ and reader.getbool(section, "usedevelop", config.option.develop))
vc.envdir = reader.getpath(section, "envdir", "{toxworkdir}/%s" % name)
vc.args_are_paths = reader.getbool(section, "args_are_paths", True)
if reader.getdefault(section, "python", None):
raise tox.exception.ConfigError(
"'python=' key was renamed to 'basepython='")
bp = next((default_factors[f] for f in factors if f in default_factors),
- sys.executable)
+ sys.executable)
vc.basepython = reader.getdefault(section, "basepython", bp)
vc._basepython_info = config.interpreters.get_info(vc.basepython)
reader.addsubstitutions(envdir=vc.envdir, envname=vc.envname,
@@ -410,8 +418,9 @@ class parseini:
break
vc.platform = platform
- vc.sitepackages = self.config.option.sitepackages or \
- reader.getbool(section, "sitepackages", False)
+ vc.sitepackages = (
+ self.config.option.sitepackages
+ or reader.getbool(section, "sitepackages", False))
vc.downloadcache = None
downloadcache = reader.getdefault(section, "downloadcache")
@@ -424,10 +433,10 @@ class parseini:
section,
"install_command",
"pip install {opts} {packages}",
- )
+ )
if '{packages}' not in vc.install_command:
raise tox.exception.ConfigError(
- "'install_command' must contain '{packages}' substitution")
+ "'install_command' must contain '{packages}' substitution")
vc.pip_pre = config.option.pre or reader.getbool(
section, "pip_pre", False)
@@ -488,10 +497,12 @@ def _split_env(env):
env = [env]
return mapcat(_expand_envstr, env)
+
def _split_factor_expr(expr):
partial_envs = _expand_envstr(expr)
return [set(e.split('-')) for e in partial_envs]
+
def _expand_envstr(envstr):
# split by commas not in groups
tokens = re.split(r'((?:\{[^}]+\})+)|,', envstr)
@@ -505,9 +516,11 @@ def _expand_envstr(envstr):
return mapcat(expand, envlist)
+
def mapcat(f, seq):
return list(itertools.chain.from_iterable(map(f, seq)))
+
class DepConfig:
def __init__(self, name, indexserver=None):
self.name = name
@@ -710,7 +723,7 @@ class IniReader:
x = self._replace(x)
finally:
assert self._subststack.pop() == (section, name)
- #print "getdefault", section, name, "returned", repr(x)
+ # print "getdefault", section, name, "returned", repr(x)
return x
def _apply_factors(self, s):
@@ -740,7 +753,7 @@ class IniReader:
else:
envkey = match_value
- if not envkey in os.environ and default is None:
+ if envkey not in os.environ and default is None:
raise tox.exception.ConfigError(
"substitution env:%r: unkown environment variable %r" %
(envkey, envkey))
@@ -750,11 +763,11 @@ class IniReader:
def _substitute_from_other_section(self, key):
if key.startswith("[") and "]" in key:
i = key.find("]")
- section, item = key[1:i], key[i+1:]
+ 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))
+ raise ValueError('%s already in %s' % (
+ (section, item), self._subststack))
x = str(self._cfg[section][item])
self._subststack.append((section, item))
try:
@@ -785,13 +798,14 @@ class IniReader:
return '{%s}' % sub_value
handlers = {
- 'env' : self._replace_env,
- None : self._replace_substitution,
- }
+ 'env': self._replace_env,
+ None: self._replace_substitution,
+ }
try:
sub_type = g['sub_type']
except KeyError:
- raise tox.exception.ConfigError("Malformed substitution; no substitution type provided")
+ raise tox.exception.ConfigError(
+ "Malformed substitution; no substitution type provided")
try:
handler = handlers[sub_type]
@@ -808,6 +822,7 @@ class IniReader:
def _parse_command(self, command):
pass
+
class CommandParser(object):
class State(object):
@@ -824,11 +839,11 @@ class CommandParser(object):
def word_has_ended():
return ((cur_char in string.whitespace and ps.word and
- ps.word[-1] not in string.whitespace) or
- (cur_char == '{' and ps.depth == 0 and not ps.word.endswith('\\')) or
- (ps.depth == 0 and ps.word and ps.word[-1] == '}') or
- (cur_char not in string.whitespace and ps.word and
- ps.word.strip() == ''))
+ ps.word[-1] not in string.whitespace) or
+ (cur_char == '{' and ps.depth == 0 and not ps.word.endswith('\\')) or
+ (ps.depth == 0 and ps.word and ps.word[-1] == '}') or
+ (cur_char not in string.whitespace and ps.word and
+ ps.word.strip() == ''))
def yield_this_word():
yieldword = ps.word
@@ -869,8 +884,8 @@ class CommandParser(object):
yield_this_word()
return ps.yield_words
+
def getcontextname():
if any(env in os.environ for env in ['JENKINS_URL', 'HUDSON_URL']):
return 'jenkins'
return None
-
diff --git a/tox/_exception.py b/tox/_exception.py
index 5244171..9917f09 100644
--- a/tox/_exception.py
+++ b/tox/_exception.py
@@ -1,16 +1,28 @@
class Error(Exception):
def __str__(self):
- return "%s: %s" %(self.__class__.__name__, self.args[0])
+ return "%s: %s" % (self.__class__.__name__, self.args[0])
+
+
class UnsupportedInterpreter(Error):
"signals an unsupported Interpreter"
+
+
class InterpreterNotFound(Error):
"signals that an interpreter could not be found"
+
+
class InvocationError(Error):
""" an error while invoking a script. """
+
+
class MissingFile(Error):
""" an error while invoking a script. """
+
+
class MissingDirectory(Error):
""" a directory did not exist. """
+
+
class MissingDependency(Error):
""" a dependency could not be found or determined. """
diff --git a/tox/_pytestplugin.py b/tox/_pytestplugin.py
index ded13ec..9d7488a 100644
--- a/tox/_pytestplugin.py
+++ b/tox/_pytestplugin.py
@@ -1,4 +1,5 @@
-import pytest, py
+import py
+import pytest
import tox
import os
import sys
@@ -10,6 +11,7 @@ from tox._venv import VirtualEnv
from tox._cmdline import Action
from tox.result import ResultLog
+
def pytest_configure():
if 'TOXENV' in os.environ:
del os.environ['TOXENV']
@@ -19,12 +21,14 @@ def pytest_configure():
def pytest_addoption(parser):
parser.addoption("--no-network", action="store_true",
- dest="no_network",
- help="don't run tests requiring network")
+ dest="no_network",
+ help="don't run tests requiring network")
+
def pytest_report_header():
return "tox comes from: %r" % (tox.__file__)
+
@pytest.fixture
def newconfig(request, tmpdir):
def newconfig(args, source=None):
@@ -41,12 +45,14 @@ def newconfig(request, tmpdir):
old.chdir()
return newconfig
+
@pytest.fixture
def cmd(request):
if request.config.option.no_network:
pytest.skip("--no-network was specified, test cannot run")
return Cmd(request)
+
class ReportExpectMock:
def __init__(self, session):
self._calls = []
@@ -61,13 +67,13 @@ class ReportExpectMock:
raise AttributeError(name)
def generic_report(*args, **kwargs):
- self._calls.append((name,)+args)
- print ("%s" %(self._calls[-1], ))
+ 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], ))
+ print ("%s" % (self._calls[-1], ))
return Action(self.session, venv, msg, args)
def getnext(self, cat):
@@ -82,7 +88,7 @@ class ReportExpectMock:
newindex += 1
raise LookupError(
"looking for %r, no reports found at >=%d in %r" %
- (cat, self._index+1, self._calls))
+ (cat, self._index + 1, self._calls))
def expect(self, cat, messagepattern="*", invert=False):
__tracebackhide__ = True
@@ -98,16 +104,17 @@ class ReportExpectMock:
if fnmatch(lmsg, messagepattern):
if invert:
raise AssertionError("found %s(%r), didn't expect it" %
- (cat, messagepattern))
+ (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))
+ "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.arg0 = args[0]
@@ -120,44 +127,54 @@ class pcallMock:
def communicate(self):
return "", ""
+
def wait(self):
pass
+
@pytest.fixture
def mocksession(request):
from tox._cmdline import Session
+
class MockSession(Session):
def __init__(self):
self._clearmocks()
self.config = request.getfuncargvalue("newconfig")([], "")
self.resultlog = ResultLog()
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,
- universal_newlines=False,
- stdout=None, stderr=None, env=None):
+ universal_newlines=False,
+ stdout=None, stderr=None, env=None):
pm = pcallMock(args, cwd, env, stdout, stderr, shell)
self._pcalls.append(pm)
return pm
return MockSession()
+
@pytest.fixture
def 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")
@@ -175,7 +192,7 @@ class Cmd:
env['PYTHONPATH'] = ":".join(filter(None, [
str(os.getcwd()), env.get('PYTHONPATH', '')]))
kw['env'] = env
- #print "env", env
+ # print "env", env
return py.std.subprocess.Popen(argv, stdout=stdout, stderr=stderr, **kw)
def run(self, *argv):
@@ -188,7 +205,7 @@ class Cmd:
f2 = p2.open("wb")
now = time.time()
popen = self.popen(argv, stdout=f1, stderr=f2,
- close_fds=(sys.platform != "win32"))
+ close_fds=(sys.platform != "win32"))
ret = popen.wait()
f1.close()
f2.close()
@@ -196,6 +213,7 @@ class Cmd:
out = getdecoded(out).splitlines()
err = p2.read("rb")
err = getdecoded(err).splitlines()
+
def dump_lines(lines, fp):
try:
for line in lines:
@@ -204,14 +222,16 @@ class Cmd:
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)
+ 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),)
+ py.io.saferepr(out),)
+
class RunResult:
def __init__(self, ret, outlines, errlines, duration):
@@ -222,8 +242,9 @@ class RunResult:
self.stderr = LineMatcher(errlines)
self.duration = duration
+
class LineMatcher:
- def __init__(self, lines):
+ def __init__(self, lines):
self.lines = lines
def str(self):
@@ -260,6 +281,7 @@ class LineMatcher:
else:
assert line == nextline
+
@pytest.fixture
def initproj(request, tmpdir):
""" create a factory function for creating example projects. """
@@ -288,16 +310,18 @@ def initproj(request, tmpdir):
)
''' % locals()})
if name not in filedefs:
- create_files(base, {name:
- {'__init__.py': '__version__ = %r' % version}})
+ create_files(base, {
+ name: {'__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,))
+ 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):
diff --git a/tox/_quickstart.py b/tox/_quickstart.py
index e7c4f03..a397cb1 100644
--- a/tox/_quickstart.py
+++ b/tox/_quickstart.py
@@ -78,11 +78,13 @@ 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:
@@ -90,17 +92,20 @@ def choice(*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
@@ -159,7 +164,7 @@ What Python versions do you want to test against? Choices:
[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'))
+ '3', choice('1', '2', '3', '4'))
if d['canned_pyenvs'] == '1':
d['py27'] = True
@@ -197,17 +202,20 @@ What extra dependencies do your tests have?''')
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(',')])
+ 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*."""
@@ -236,7 +244,8 @@ def generate(d, overwrite=True, silent=False):
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('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.
''')
diff --git a/tox/_venv.py b/tox/_venv.py
index 926a893..f642be0 100644
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -1,11 +1,13 @@
from __future__ import with_statement
-import sys, os
+import os
+import sys
import re
import codecs
import py
import tox
from tox._config import DepConfig
+
class CreationConfig:
def __init__(self, md5, python, version, sitepackages,
develop, deps):
@@ -43,11 +45,12 @@ class CreationConfig:
def matches(self, other):
return (other and self.md5 == other.md5
- and self.python == other.python
- and self.version == other.version
- and self.sitepackages == other.sitepackages
- and self.develop == other.develop
- and self.deps == other.deps)
+ and self.python == other.python
+ and self.version == other.version
+ and self.sitepackages == other.sitepackages
+ and self.develop == other.develop
+ and self.deps == other.deps)
+
class VirtualEnv(object):
def __init__(self, envconfig=None, session=None):
@@ -61,7 +64,7 @@ class VirtualEnv(object):
return self.envconfig.envname
def __repr__(self):
- return "<VirtualEnv at %r>" %(self.path)
+ return "<VirtualEnv at %r>" % (self.path)
def getcommandpath(self, name=None, venv=True, cwd=None):
if name is None:
@@ -81,7 +84,7 @@ class VirtualEnv(object):
p = py.path.local.sysfind(name)
if p is None:
raise tox.exception.InvocationError(
- "could not find executable %r" % (name,))
+ "could not find executable %r" % (name,))
# p is not found in virtualenv script/bin dir
if venv:
if not self.is_allowed_external(p):
@@ -89,15 +92,16 @@ class VirtualEnv(object):
"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
+ "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)]
+ 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:
@@ -116,7 +120,7 @@ class VirtualEnv(object):
action = self.session.newaction(self, "update")
rconfig = CreationConfig.readconfig(self.path_config)
if not self.envconfig.recreate and rconfig and \
- rconfig.matches(self._getliveconfig()):
+ rconfig.matches(self._getliveconfig()):
action.info("reusing", self.envconfig.envdir)
return
if rconfig is None:
@@ -167,7 +171,7 @@ class VirtualEnv(object):
return re.match(self.envconfig.platform, sys.platform)
def create(self, action=None):
- #if self.getcommandpath("activate").dirpath().check():
+ # if self.getcommandpath("activate").dirpath().check():
# return
if action is None:
action = self.session.newaction(self, "create")
@@ -179,11 +183,11 @@ class VirtualEnv(object):
# add interpreter explicitly, to prevent using
# default (virtualenv.ini)
args.extend(['--python', str(config_interpreter)])
- #if sys.platform == "win32":
+ # if sys.platform == "win32":
# f, path, _ = py.std.imp.find_module("virtualenv")
# f.close()
# args[:1] = [str(config_interpreter), str(path)]
- #else:
+ # else:
self.session.make_emptydir(self.path)
basepath = self.path.dirpath()
basepath.ensure(dir=1)
@@ -191,7 +195,6 @@ class VirtualEnv(object):
self._pcall(args, venv=False, action=action, cwd=basepath)
self.just_created = True
-
def finish(self):
self._getliveconfig().writeconfig(self.path_config)
@@ -204,8 +207,8 @@ class VirtualEnv(object):
name = output.strip()
egg_info = setupdir.join('.'.join((name, 'egg-info')))
for conf_file in (setup_py, setup_cfg):
- if (not egg_info.check() or (conf_file.check()
- and conf_file.mtime() > egg_info.mtime())):
+ if (not egg_info.check()
+ or (conf_file.check() and conf_file.mtime() > egg_info.mtime())):
return True
return False
@@ -240,8 +243,7 @@ class VirtualEnv(object):
deps = self._getresolvedeps()
if deps:
depinfo = ", ".join(map(str, deps))
- action.setactivity("installdeps",
- "%s" % depinfo)
+ action.setactivity("installdeps", "%s" % depinfo)
self._install(deps, action=action)
def _installopts(self, indexserver):
@@ -261,10 +263,10 @@ class VirtualEnv(object):
argv = self.envconfig.install_command[:]
# use pip-script on win32 to avoid the executable locking
i = argv.index('{packages}')
- argv[i:i+1] = packages
+ argv[i:i + 1] = packages
if '{opts}' in argv:
i = argv.index('{opts}')
- argv[i:i+1] = list(options)
+ argv[i:i + 1] = list(options)
for x in ('PIP_RESPECT_VIRTUALENV', 'PIP_REQUIRE_VIRTUALENV',
'__PYVENV_LAUNCHER__'):
try:
@@ -301,7 +303,7 @@ class VirtualEnv(object):
if self.envconfig.config.option.sethome:
extraenv = hack_home_env(
homedir=self.envconfig.envtmpdir.join("pseudo-home"),
- index_url = ixserver.url)
+ index_url=ixserver.url)
else:
extraenv = {}
@@ -351,7 +353,8 @@ class VirtualEnv(object):
ignore_ret = False
try:
- self._pcall(argv, cwd=cwd, action=action, redirect=redirect, ignore_ret=ignore_ret)
+ self._pcall(argv, cwd=cwd, action=action, redirect=redirect,
+ ignore_ret=ignore_ret)
except tox.exception.InvocationError:
val = sys.exc_info()[1]
self.session.report.error(str(val))
@@ -362,7 +365,7 @@ class VirtualEnv(object):
raise
def _pcall(self, args, venv=True, cwd=None, extraenv={},
- action=None, redirect=True, ignore_ret=False):
+ action=None, redirect=True, ignore_ret=False):
for name in ("VIRTUALENV_PYTHON", "PYTHONDONTWRITEBYTECODE"):
try:
del os.environ[name]
diff --git a/tox/_verlib.py b/tox/_verlib.py
index a234176..a2e7471 100644
--- a/tox/_verlib.py
+++ b/tox/_verlib.py
@@ -10,10 +10,12 @@ licensed under the PSF license (i guess)
import re
+
class IrrationalVersionError(Exception):
"""This is an irrational version."""
pass
+
class HugeMajorVersionNumError(IrrationalVersionError):
"""An irrational version because the major version number is huge
(often because a year or date was used).
@@ -52,6 +54,7 @@ VERSION_RE = re.compile(r'''
(?P<postdev>(\.post(?P<post>\d+))?(\.dev(?P<dev>\d+))?)?
$''', re.VERBOSE)
+
class NormalizedVersion(object):
"""A rational version.
@@ -136,7 +139,8 @@ class NormalizedVersion(object):
parts.append(FINAL_MARKER)
self.parts = tuple(parts)
if error_on_huge_major_num and self.parts[0][0] > 1980:
- raise HugeMajorVersionNumError("huge major version number, %r, "
+ raise HugeMajorVersionNumError(
+ "huge major version number, %r, "
"which might cause future problems: %r" % (self.parts[0][0], s))
def _parse_numdots(self, s, full_ver_str, drop_trailing_zeros=True,
@@ -154,7 +158,8 @@ class NormalizedVersion(object):
nums = []
for n in s.split("."):
if len(n) > 1 and n[0] == '0':
- raise IrrationalVersionError("cannot have leading zero in "
+ raise IrrationalVersionError(
+ "cannot have leading zero in "
"version number segment: '%s' in %r" % (n, full_ver_str))
nums.append(int(n))
if drop_trailing_zeros:
@@ -193,7 +198,7 @@ class NormalizedVersion(object):
def _cannot_compare(self, other):
raise TypeError("cannot compare %s and %s"
- % (type(self).__name__, type(other).__name__))
+ % (type(self).__name__, type(other).__name__))
def __eq__(self, other):
if not isinstance(other, NormalizedVersion):
@@ -217,6 +222,7 @@ class NormalizedVersion(object):
def __ge__(self, other):
return self.__eq__(other) or self.__gt__(other)
+
def suggest_normalized_version(s):
"""Suggest a normalized version close to the given version string.
@@ -272,7 +278,7 @@ def suggest_normalized_version(s):
rs = rs[1:]
# Clean leading '0's on numbers.
- #TODO: unintended side-effect on, e.g., "2003.05.09"
+ # TODO: unintended side-effect on, e.g., "2003.05.09"
# PyPI stats: 77 (~2%) better
rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs)
@@ -318,7 +324,6 @@ def suggest_normalized_version(s):
# PyPI stats: ~21 (0.62%) better
rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs)
-
# Tcl/Tk uses "px" for their post release markers
rs = re.sub(r"p(\d+)$", r".post\1", rs)
@@ -328,4 +333,3 @@ def suggest_normalized_version(s):
except IrrationalVersionError:
pass
return None
-
diff --git a/tox/interpreters.py b/tox/interpreters.py
index 241651f..76075b8 100644
--- a/tox/interpreters.py
+++ b/tox/interpreters.py
@@ -3,6 +3,7 @@ import py
import re
import inspect
+
class Interpreters:
def __init__(self):
self.name2executable = {}
@@ -42,20 +43,21 @@ class Interpreters:
envdir = str(envdir)
try:
res = exec_on_interpreter(info.executable,
- [inspect.getsource(sitepackagesdir),
- "print (sitepackagesdir(%r))" % envdir])
+ [inspect.getsource(sitepackagesdir),
+ "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"]
+
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,
@@ -63,6 +65,7 @@ def run_and_get_interpreter_info(name, executable):
else:
return InterpreterInfo(name, executable, **result)
+
def exec_on_interpreter(executable, source):
if isinstance(source, list):
source = "\n".join(source)
@@ -80,6 +83,7 @@ def exec_on_interpreter(executable, source):
"could not decode %r" % out)
return result
+
class ExecFailed(Exception):
def __init__(self, executable, source, out, err):
self.executable = executable
@@ -87,6 +91,7 @@ class ExecFailed(Exception):
self.out = out
self.err = err
+
class InterpreterInfo:
runnable = True
@@ -99,10 +104,12 @@ class InterpreterInfo:
def __str__(self):
return "<executable at %s, version_info %s>" % (
- self.executable, self.version_info)
+ self.executable, self.version_info)
+
class NoInterpreterInfo:
runnable = False
+
def __init__(self, name, executable=None,
out=None, err="not found"):
self.name = name
@@ -124,9 +131,10 @@ if sys.platform != "win32":
else:
# Exceptions to the usual windows mapping
win32map = {
- 'python': sys.executable,
- 'jython': "c:\jython2.5.1\jython.bat",
+ 'python': sys.executable,
+ '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)"
@@ -162,11 +170,13 @@ else:
if m:
return locate_via_py(*m.groups())
+
def pyinfo():
import sys
return dict(version_info=tuple(sys.version_info),
sysplatform=sys.platform)
+
def sitepackagesdir(envdir):
from distutils.sysconfig import get_python_lib
return dict(dir=get_python_lib(prefix=envdir))
diff --git a/tox/result.py b/tox/result.py
index ee5ad09..7bedd3f 100644
--- a/tox/result.py
+++ b/tox/result.py
@@ -46,23 +46,24 @@ class EnvLog:
def set_python_info(self, pythonexecutable):
pythonexecutable = py.path.local(pythonexecutable)
out = pythonexecutable.sysexec("-c",
- "import sys; "
- "print (sys.executable);"
- "print (list(sys.version_info)); "
- "print (sys.version)")
+ "import sys; "
+ "print (sys.executable);"
+ "print (list(sys.version_info)); "
+ "print (sys.version)")
lines = out.splitlines()
executable = lines.pop(0)
version_info = eval(lines.pop(0))
version = "\n".join(lines)
self.dict["python"] = dict(
executable=executable,
- version_info = version_info,
- version = version)
+ version_info=version_info,
+ version=version)
def get_commandlog(self, name):
l = self.dict.setdefault(name, [])
return CommandLog(self, l)
+
class CommandLog:
def __init__(self, envlog, list):
self.envlog = envlog