diff options
author | holger krekel <holger@merlinux.eu> | 2015-05-08 13:15:14 +0200 |
---|---|---|
committer | holger krekel <holger@merlinux.eu> | 2015-05-08 13:15:14 +0200 |
commit | 6e2e1a62b903a29bfeca35c680789a8e959786fa (patch) | |
tree | 10fbc8da4a1c4bed91cd36adc8ca66806f3050f1 /tox | |
parent | ecdad82f66a6e6678276d7101f7d0457de27ecd7 (diff) | |
download | tox-6e2e1a62b903a29bfeca35c680789a8e959786fa.tar.gz |
introduce little plugin system based on pluggy
and refactor/streamline some code with relation to
getting executables
Diffstat (limited to 'tox')
-rw-r--r-- | tox/__init__.py | 2 | ||||
-rw-r--r-- | tox/_cmdline.py | 5 | ||||
-rw-r--r-- | tox/_config.py | 66 | ||||
-rw-r--r-- | tox/_venv.py | 2 | ||||
-rw-r--r-- | tox/interpreters.py | 55 |
5 files changed, 84 insertions, 46 deletions
diff --git a/tox/__init__.py b/tox/__init__.py index 7869fcb..5f3f3ad 100644 --- a/tox/__init__.py +++ b/tox/__init__.py @@ -1,6 +1,8 @@ # __version__ = '2.0.0.dev1' +from .hookspecs import hookspec, hookimpl # noqa + class exception: class Error(Exception): diff --git a/tox/_cmdline.py b/tox/_cmdline.py index 0236d17..3dd9582 100644 --- a/tox/_cmdline.py +++ b/tox/_cmdline.py @@ -24,7 +24,7 @@ def now(): def main(args=None): try: - config = parseconfig(args, 'tox') + config = parseconfig(args) retcode = Session(config).runcommand() raise SystemExit(retcode) except KeyboardInterrupt: @@ -551,8 +551,7 @@ class Session: for envconfig in self.config.envconfigs.values(): self.report.line("[testenv:%s]" % envconfig.envname, bold=True) self.report.line(" basepython=%s" % envconfig.basepython) - self.report.line(" _basepython_info=%s" % - envconfig._basepython_info) + self.report.line(" pythoninfo=%s" % (envconfig.python_info,)) self.report.line(" envpython=%s" % envconfig.envpython) self.report.line(" envtmpdir=%s" % envconfig.envtmpdir) self.report.line(" envbindir=%s" % envconfig.envbindir) diff --git a/tox/_config.py b/tox/_config.py index 4468d86..d5e8a31 100644 --- a/tox/_config.py +++ b/tox/_config.py @@ -8,8 +8,10 @@ import shlex import string import pkg_resources import itertools +import pluggy -from tox.interpreters import Interpreters +import tox.interpreters +from tox import hookspecs import py @@ -22,20 +24,43 @@ default_factors = {'jython': 'jython', 'pypy': 'pypy', 'pypy3': 'pypy3', for version in '24,25,26,27,30,31,32,33,34,35'.split(','): default_factors['py' + version] = 'python%s.%s' % tuple(version) +hookimpl = pluggy.HookimplMarker("tox") -def parseconfig(args=None, pkg=None): + +def get_plugin_manager(): + # initialize plugin manager + pm = pluggy.PluginManager("tox") + pm.add_hookspecs(hookspecs) + pm.register(tox._config) + pm.register(tox.interpreters) + pm.load_setuptools_entrypoints("tox") + pm.check_pending() + return pm + + +def parseconfig(args=None): """ :param list[str] args: Optional list of arguments. :type pkg: str :rtype: :class:`Config` :raise SystemExit: toxinit file is not found """ + + pm = get_plugin_manager() + if args is None: args = sys.argv[1:] - parser = prepare_parse(pkg) - opts = parser.parse_args(args) - config = Config() - config.option = opts + + # prepare command line options + parser = argparse.ArgumentParser(description=__doc__) + pm.hook.tox_addoption(parser=parser) + + # parse command line options + option = parser.parse_args(args) + interpreters = tox.interpreters.Interpreters(hook=pm.hook) + config = Config(pluginmanager=pm, option=option, interpreters=interpreters) + + # parse ini file basename = config.option.configfile if os.path.isabs(basename): inipath = py.path.local(basename) @@ -52,6 +77,10 @@ def parseconfig(args=None, pkg=None): exn = sys.exc_info()[1] # Use stdout to match test expectations py.builtin.print_("ERROR: " + str(exn)) + + # post process config object + pm.hook.tox_configure(config=config) + return config @@ -63,10 +92,8 @@ def feedback(msg, sysexit=False): 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__)) + version = tox.__version__ + py.builtin.print_("%s imported from %s" % (version, tox.__file__)) raise SystemExit(0) @@ -78,10 +105,9 @@ class CountAction(argparse.Action): setattr(namespace, self.dest, 0) -def prepare_parse(pkgname): - parser = argparse.ArgumentParser(description=__doc__,) +@hookimpl +def tox_addoption(parser): # formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.pkgname = pkgname parser.add_argument("--version", nargs=0, action=VersionAction, dest="version", help="report version information to stdout.") @@ -153,10 +179,12 @@ def prepare_parse(pkgname): class Config(object): - def __init__(self): + def __init__(self, pluginmanager, option, interpreters): self.envconfigs = {} self.invocationcwd = py.path.local() - self.interpreters = Interpreters() + self.interpreters = interpreters + self.pluginmanager = pluginmanager + self.option = option @property def homedir(self): @@ -192,10 +220,14 @@ class VenvConfig: def envsitepackagesdir(self): self.getsupportedinterpreter() # for throwing exceptions x = self.config.interpreters.get_sitepackagesdir( - info=self._basepython_info, + info=self.python_info, envdir=self.envdir) return x + @property + def python_info(self): + return self.config.interpreters.get_info(self.basepython) + def getsupportedinterpreter(self): if sys.platform == "win32" and self.basepython and \ "jython" in self.basepython: @@ -356,7 +388,7 @@ class parseini: bp = next((default_factors[f] for f in factors if f in default_factors), 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, envbindir=vc.envbindir, envpython=vc.envpython, envsitepackagesdir=vc.envsitepackagesdir) diff --git a/tox/_venv.py b/tox/_venv.py index 9114e69..58587e4 100644 --- a/tox/_venv.py +++ b/tox/_venv.py @@ -143,7 +143,7 @@ class VirtualEnv(object): self.envconfig.deps, v) def _getliveconfig(self): - python = self.envconfig._basepython_info.executable + python = self.envconfig.python_info.executable md5 = getdigest(python) version = tox.__version__ sitepackages = self.envconfig.sitepackages diff --git a/tox/interpreters.py b/tox/interpreters.py index 76075b8..98a5c40 100644 --- a/tox/interpreters.py +++ b/tox/interpreters.py @@ -2,12 +2,14 @@ import sys import py import re import inspect +from tox import hookimpl class Interpreters: - def __init__(self): + def __init__(self, hook): self.name2executable = {} self.executable2info = {} + self.hook = hook def get_executable(self, name): """ return path object to the executable for the given @@ -18,8 +20,9 @@ class Interpreters: try: return self.name2executable[name] except KeyError: - self.name2executable[name] = e = find_executable(name) - return e + exe = self.hook.tox_get_python_executable(name=name) + self.name2executable[name] = exe + return exe def get_info(self, name=None, executable=None): if name is None and executable is None: @@ -125,31 +128,13 @@ class NoInterpreterInfo: return "<executable not found for: %s>" % self.name if sys.platform != "win32": - def find_executable(name): + @hookimpl + def tox_get_python_executable(name): return py.path.local.sysfind(name) else: - # Exceptions to the usual windows mapping - win32map = { - '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)" - 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): + @hookimpl + def tox_get_python_executable(name): p = py.path.local.sysfind(name) if p: return p @@ -170,6 +155,26 @@ else: if m: return locate_via_py(*m.groups()) + # Exceptions to the usual windows mapping + win32map = { + '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)" + 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 pyinfo(): import sys |