2 new commits in tox:
https://bitbucket.org/hpk42/tox/commits/850fb37c6062/
Changeset: 850fb37c6062
User: hpk42
Date: 2015-05-08 11:16:20+00:00
Summary: Backed out changeset cc1933175162
Affected #: 13 files
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 doc/conf.py
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -48,8 +48,8 @@
# built documents.
#
# The short X.Y version.
-release = "2.0"
-version = "2.0.0"
+release = "1.9"
+version = "1.9.0"
# The full version, including alpha/beta/rc tags.
# The language for content autogenerated by Sphinx. Refer to documentation
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 doc/index.txt
--- a/doc/index.txt
+++ b/doc/index.txt
@@ -5,7 +5,7 @@
---------------------------------------------
``tox`` aims to automate and standardize testing in Python. It is part
-of a larger vision of easing the packaging, testing and release process
+of a larger vision of easing the packaging, testing and release process
of Python software.
What is Tox?
@@ -21,7 +21,6 @@
* acting as a frontend to Continuous Integration servers, greatly
reducing boilerplate and merging CI and shell-based testing.
-
Basic example
-----------------
@@ -63,10 +62,10 @@
- test-tool agnostic: runs py.test, nose or unittests in a uniform manner
-* :doc:`(new in 2.0) plugin system <plugins>` to modify tox execution with
simple hooks.
+* supports :ref:`using different / multiple PyPI index servers <multiindex>`
* uses pip_ and setuptools_ by default. Experimental
- support for configuring the installer command
+ support for configuring the installer command
through :confval:`install_command=ARGV`.
* **cross-Python compatible**: CPython-2.6, 2.7, 3.2 and higher,
@@ -75,11 +74,11 @@
* **cross-platform**: Windows and Unix style environments
* **integrates with continuous integration servers** like Jenkins_
- (formerly known as Hudson) and helps you to avoid boilerplatish
+ (formerly known as Hudson) and helps you to avoid boilerplatish
and platform-specific build-step hacks.
* **full interoperability with devpi**: is integrated with and
- is used for testing in the devpi_ system, a versatile pypi
+ is used for testing in the devpi_ system, a versatile pypi
index server and release managing tool.
* **driven by a simple ini-style config file**
@@ -90,9 +89,6 @@
* **professionally** :doc:`supported <support>`
-* supports :ref:`using different / multiple PyPI index servers <multiindex>`
-
-
.. _pypy: http://pypy.org
.. _`tox.ini`: :doc:configfile
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 doc/plugins.txt
--- a/doc/plugins.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-.. be in -*- rst -*- mode!
-
-tox plugins
-===========
-
-.. versionadded:: 2.0
-
-With tox-2.0 a few aspects of tox running can be experimentally modified
-by writing hook functions. We expect the list of hook function to grow
-over time.
-
-writing a setuptools entrypoints plugin
----------------------------------------
-
-If you have a ``tox_MYPLUGIN.py`` module you could use the following
-rough ``setup.py`` to make it into a package which you can upload to the
-Python packaging index::
-
- # content of setup.py
- from setuptools import setup
-
- if __name__ == "__main__":
- setup(
- name='tox-MYPLUGIN',
- description='tox plugin decsription',
- license="MIT license",
- version='0.1',
- py_modules=['tox_MYPLUGIN'],
- entry_points={'tox': ['MYPLUGIN = tox_MYPLUGIN']},
- install_requires=['tox>=2.0'],
- )
-
-You can then install the plugin to develop it via::
-
- pip install -e .
-
-and later publish it.
-
-The ``entry_points`` part allows tox to see your plugin during startup.
-
-
-Writing hook implementations
-----------------------------
-
-A plugin module needs can define one or more hook implementation functions::
-
- from tox import hookimpl
-
- @hookimpl
- def tox_addoption(parser):
- # add your own command line options
-
-
- @hookimpl
- def tox_configure(config):
- # post process tox configuration after cmdline/ini file have
- # been parsed
-
-If you put this into a module and make it pypi-installable with the ``tox``
-entry point you'll get your code executed as part of a tox run.
-
-
-
-tox hook specifications
-----------------------------
-
-.. automodule:: tox.hookspecs
- :members:
-
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 setup.py
--- a/setup.py
+++ b/setup.py
@@ -18,7 +18,7 @@
def main():
version = sys.version_info[:2]
- install_requires = ['virtualenv>=1.11.2', 'py>=1.4.17',
'pluggy>=0.3.0,<0.4.0']
+ install_requires = ['virtualenv>=1.11.2', 'py>=1.4.17', ]
if version < (2, 7):
install_requires += ['argparse']
setup(
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 tests/test_config.py
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -6,6 +6,7 @@
import tox
import tox._config
from tox._config import * # noqa
+from tox._config import _split_env
from tox._venv import VirtualEnv
@@ -1560,16 +1561,31 @@
])
[email protected]("cmdline,envlist", [
- ("-e py26", ['py26']),
- ("-e py26,py33", ['py26', 'py33']),
- ("-e py26,py26", ['py26', 'py26']),
- ("-e py26,py33 -e py33,py27", ['py26', 'py33', 'py33', 'py27'])
-])
-def test_env_spec(cmdline, envlist):
- args = cmdline.split()
- config = parseconfig(args)
- assert config.envlist == envlist
+class TestArgumentParser:
+
+ def test_dash_e_single_1(self):
+ parser = prepare_parse('testpkg')
+ args = parser.parse_args('-e py26'.split())
+ envlist = _split_env(args.env)
+ assert envlist == ['py26']
+
+ def test_dash_e_single_2(self):
+ parser = prepare_parse('testpkg')
+ args = parser.parse_args('-e py26,py33'.split())
+ envlist = _split_env(args.env)
+ assert envlist == ['py26', 'py33']
+
+ def test_dash_e_same(self):
+ parser = prepare_parse('testpkg')
+ args = parser.parse_args('-e py26,py26'.split())
+ envlist = _split_env(args.env)
+ assert envlist == ['py26', 'py26']
+
+ def test_dash_e_combine(self):
+ parser = prepare_parse('testpkg')
+ args = parser.parse_args('-e py26,py25,py33 -e py33,py27'.split())
+ envlist = _split_env(args.env)
+ assert envlist == ['py26', 'py25', 'py33', 'py33', 'py27']
class TestCommandParser:
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 tests/test_interpreters.py
--- a/tests/test_interpreters.py
+++ b/tests/test_interpreters.py
@@ -3,13 +3,11 @@
import pytest
from tox.interpreters import * # noqa
-from tox._config import get_plugin_manager
@pytest.fixture
def interpreters():
- pm = get_plugin_manager()
- return Interpreters(hook=pm.hook)
+ return Interpreters()
@pytest.mark.skipif("sys.platform != 'win32'")
@@ -30,8 +28,8 @@
assert locate_via_py('3', '2') == sys.executable
-def test_tox_get_python_executable():
- p = tox_get_python_executable(sys.executable)
+def test_find_executable():
+ p = find_executable(sys.executable)
assert p == py.path.local(sys.executable)
for ver in [""] + "2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3".split():
name = "python%s" % ver
@@ -44,7 +42,7 @@
else:
if not py.path.local.sysfind(name):
continue
- p = tox_get_python_executable(name)
+ p = find_executable(name)
assert p
popen = py.std.subprocess.Popen([str(p), '-V'],
stderr=py.std.subprocess.PIPE)
@@ -57,7 +55,7 @@
def sysfind(x):
return "hello"
monkeypatch.setattr(py.path.local, "sysfind", sysfind)
- t = tox_get_python_executable("qweqwe")
+ t = find_executable("qweqwe")
assert t == "hello"
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 tests/test_venv.py
--- a/tests/test_venv.py
+++ b/tests/test_venv.py
@@ -65,7 +65,7 @@
# assert Envconfig.toxworkdir in args
assert venv.getcommandpath("easy_install", cwd=py.path.local())
interp = venv._getliveconfig().python
- assert interp == venv.envconfig.python_info.executable
+ assert interp == venv.envconfig._basepython_info.executable
assert venv.path_config.check(exists=False)
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -22,9 +22,7 @@
deps = pytest-flakes>=0.2
pytest-pep8
-commands =
- py.test --flakes -m flakes tox tests
- py.test --pep8 -m pep8 tox tests
+commands = py.test -x --flakes --pep8 tox tests
[testenv:dev]
# required to make looponfail reload on every source code change
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 tox/__init__.py
--- a/tox/__init__.py
+++ b/tox/__init__.py
@@ -1,8 +1,6 @@
#
__version__ = '2.0.0.dev1'
-from .hookspecs import hookspec, hookimpl # noqa
-
class exception:
class Error(Exception):
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 tox/_cmdline.py
--- a/tox/_cmdline.py
+++ b/tox/_cmdline.py
@@ -24,7 +24,7 @@
def main(args=None):
try:
- config = parseconfig(args)
+ config = parseconfig(args, 'tox')
retcode = Session(config).runcommand()
raise SystemExit(retcode)
except KeyboardInterrupt:
@@ -551,7 +551,8 @@
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(" pythoninfo=%s" % (envconfig.python_info,))
+ self.report.line(" _basepython_info=%s" %
+ envconfig._basepython_info)
self.report.line(" envpython=%s" % envconfig.envpython)
self.report.line(" envtmpdir=%s" % envconfig.envtmpdir)
self.report.line(" envbindir=%s" % envconfig.envbindir)
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 tox/_config.py
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -8,10 +8,8 @@
import string
import pkg_resources
import itertools
-import pluggy
-import tox.interpreters
-from tox import hookspecs
+from tox.interpreters import Interpreters
import py
@@ -24,43 +22,20 @@
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 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):
+def parseconfig(args=None, pkg=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:]
-
- # 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
+ parser = prepare_parse(pkg)
+ opts = parser.parse_args(args)
+ config = Config()
+ config.option = opts
basename = config.option.configfile
if os.path.isabs(basename):
inipath = py.path.local(basename)
@@ -77,10 +52,6 @@
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
@@ -92,8 +63,10 @@
class VersionAction(argparse.Action):
def __call__(self, argparser, *args, **kwargs):
- version = tox.__version__
- py.builtin.print_("%s imported from %s" % (version, tox.__file__))
+ name = argparser.pkgname
+ mod = __import__(name)
+ version = mod.__version__
+ py.builtin.print_("%s imported from %s" % (version, mod.__file__))
raise SystemExit(0)
@@ -105,9 +78,10 @@
setattr(namespace, self.dest, 0)
-@hookimpl
-def tox_addoption(parser):
+def prepare_parse(pkgname):
+ parser = argparse.ArgumentParser(description=__doc__,)
# formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser.pkgname = pkgname
parser.add_argument("--version", nargs=0, action=VersionAction,
dest="version",
help="report version information to stdout.")
@@ -179,12 +153,10 @@
class Config(object):
- def __init__(self, pluginmanager, option, interpreters):
+ def __init__(self):
self.envconfigs = {}
self.invocationcwd = py.path.local()
- self.interpreters = interpreters
- self.pluginmanager = pluginmanager
- self.option = option
+ self.interpreters = Interpreters()
@property
def homedir(self):
@@ -220,14 +192,10 @@
def envsitepackagesdir(self):
self.getsupportedinterpreter() # for throwing exceptions
x = self.config.interpreters.get_sitepackagesdir(
- info=self.python_info,
+ info=self._basepython_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:
@@ -388,7 +356,7 @@
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 -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -143,7 +143,7 @@
self.envconfig.deps, v)
def _getliveconfig(self):
- python = self.envconfig.python_info.executable
+ python = self.envconfig._basepython_info.executable
md5 = getdigest(python)
version = tox.__version__
sitepackages = self.envconfig.sitepackages
diff -r cc1933175162c4bb01669912a57df6fba4be5780 -r
850fb37c60625112b2bf5ad21373d2804be98336 tox/interpreters.py
--- a/tox/interpreters.py
+++ b/tox/interpreters.py
@@ -2,14 +2,12 @@
import py
import re
import inspect
-from tox import hookimpl
class Interpreters:
- def __init__(self, hook):
+ def __init__(self):
self.name2executable = {}
self.executable2info = {}
- self.hook = hook
def get_executable(self, name):
""" return path object to the executable for the given
@@ -20,9 +18,8 @@
try:
return self.name2executable[name]
except KeyError:
- exe = self.hook.tox_get_python_executable(name=name)
- self.name2executable[name] = exe
- return exe
+ self.name2executable[name] = e = find_executable(name)
+ return e
def get_info(self, name=None, executable=None):
if name is None and executable is None:
@@ -128,13 +125,31 @@
return "<executable not found for: %s>" % self.name
if sys.platform != "win32":
- @hookimpl
- def tox_get_python_executable(name):
+ def find_executable(name):
return py.path.local.sysfind(name)
else:
- @hookimpl
- def tox_get_python_executable(name):
+ # 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):
p = py.path.local.sysfind(name)
if p:
return p
@@ -155,26 +170,6 @@
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
https://bitbucket.org/hpk42/tox/commits/581c658b9b39/
Changeset: 581c658b9b39
Branch: pluggy
User: hpk42
Date: 2015-05-08 11:18:23+00:00
Summary: introduce little plugin system which allows to add command line
options,
perform extra configuration and determine how python executables are found
(see hookspec)
Affected #: 14 files
diff -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 doc/conf.py
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -48,8 +48,8 @@
# built documents.
#
# The short X.Y version.
-release = "1.9"
-version = "1.9.0"
+release = "2.0"
+version = "2.0.0"
# The full version, including alpha/beta/rc tags.
# The language for content autogenerated by Sphinx. Refer to documentation
diff -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 doc/index.txt
--- a/doc/index.txt
+++ b/doc/index.txt
@@ -5,7 +5,7 @@
---------------------------------------------
``tox`` aims to automate and standardize testing in Python. It is part
-of a larger vision of easing the packaging, testing and release process
+of a larger vision of easing the packaging, testing and release process
of Python software.
What is Tox?
@@ -21,6 +21,7 @@
* acting as a frontend to Continuous Integration servers, greatly
reducing boilerplate and merging CI and shell-based testing.
+
Basic example
-----------------
@@ -62,10 +63,10 @@
- test-tool agnostic: runs py.test, nose or unittests in a uniform manner
-* supports :ref:`using different / multiple PyPI index servers <multiindex>`
+* :doc:`(new in 2.0) plugin system <plugins>` to modify tox execution with
simple hooks.
* uses pip_ and setuptools_ by default. Experimental
- support for configuring the installer command
+ support for configuring the installer command
through :confval:`install_command=ARGV`.
* **cross-Python compatible**: CPython-2.6, 2.7, 3.2 and higher,
@@ -74,11 +75,11 @@
* **cross-platform**: Windows and Unix style environments
* **integrates with continuous integration servers** like Jenkins_
- (formerly known as Hudson) and helps you to avoid boilerplatish
+ (formerly known as Hudson) and helps you to avoid boilerplatish
and platform-specific build-step hacks.
* **full interoperability with devpi**: is integrated with and
- is used for testing in the devpi_ system, a versatile pypi
+ is used for testing in the devpi_ system, a versatile pypi
index server and release managing tool.
* **driven by a simple ini-style config file**
@@ -89,6 +90,9 @@
* **professionally** :doc:`supported <support>`
+* supports :ref:`using different / multiple PyPI index servers <multiindex>`
+
+
.. _pypy: http://pypy.org
.. _`tox.ini`: :doc:configfile
diff -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 doc/plugins.txt
--- /dev/null
+++ b/doc/plugins.txt
@@ -0,0 +1,69 @@
+.. be in -*- rst -*- mode!
+
+tox plugins
+===========
+
+.. versionadded:: 2.0
+
+With tox-2.0 a few aspects of tox running can be experimentally modified
+by writing hook functions. We expect the list of hook function to grow
+over time.
+
+writing a setuptools entrypoints plugin
+---------------------------------------
+
+If you have a ``tox_MYPLUGIN.py`` module you could use the following
+rough ``setup.py`` to make it into a package which you can upload to the
+Python packaging index::
+
+ # content of setup.py
+ from setuptools import setup
+
+ if __name__ == "__main__":
+ setup(
+ name='tox-MYPLUGIN',
+ description='tox plugin decsription',
+ license="MIT license",
+ version='0.1',
+ py_modules=['tox_MYPLUGIN'],
+ entry_points={'tox': ['MYPLUGIN = tox_MYPLUGIN']},
+ install_requires=['tox>=2.0'],
+ )
+
+You can then install the plugin to develop it via::
+
+ pip install -e .
+
+and later publish it.
+
+The ``entry_points`` part allows tox to see your plugin during startup.
+
+
+Writing hook implementations
+----------------------------
+
+A plugin module needs can define one or more hook implementation functions::
+
+ from tox import hookimpl
+
+ @hookimpl
+ def tox_addoption(parser):
+ # add your own command line options
+
+
+ @hookimpl
+ def tox_configure(config):
+ # post process tox configuration after cmdline/ini file have
+ # been parsed
+
+If you put this into a module and make it pypi-installable with the ``tox``
+entry point you'll get your code executed as part of a tox run.
+
+
+
+tox hook specifications
+----------------------------
+
+.. automodule:: tox.hookspecs
+ :members:
+
diff -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 setup.py
--- a/setup.py
+++ b/setup.py
@@ -18,7 +18,7 @@
def main():
version = sys.version_info[:2]
- install_requires = ['virtualenv>=1.11.2', 'py>=1.4.17', ]
+ install_requires = ['virtualenv>=1.11.2', 'py>=1.4.17',
'pluggy>=0.3.0,<0.4.0']
if version < (2, 7):
install_requires += ['argparse']
setup(
diff -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 tests/test_config.py
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -6,7 +6,6 @@
import tox
import tox._config
from tox._config import * # noqa
-from tox._config import _split_env
from tox._venv import VirtualEnv
@@ -1561,31 +1560,16 @@
])
-class TestArgumentParser:
-
- def test_dash_e_single_1(self):
- parser = prepare_parse('testpkg')
- args = parser.parse_args('-e py26'.split())
- envlist = _split_env(args.env)
- assert envlist == ['py26']
-
- def test_dash_e_single_2(self):
- parser = prepare_parse('testpkg')
- args = parser.parse_args('-e py26,py33'.split())
- envlist = _split_env(args.env)
- assert envlist == ['py26', 'py33']
-
- def test_dash_e_same(self):
- parser = prepare_parse('testpkg')
- args = parser.parse_args('-e py26,py26'.split())
- envlist = _split_env(args.env)
- assert envlist == ['py26', 'py26']
-
- def test_dash_e_combine(self):
- parser = prepare_parse('testpkg')
- args = parser.parse_args('-e py26,py25,py33 -e py33,py27'.split())
- envlist = _split_env(args.env)
- assert envlist == ['py26', 'py25', 'py33', 'py33', 'py27']
[email protected]("cmdline,envlist", [
+ ("-e py26", ['py26']),
+ ("-e py26,py33", ['py26', 'py33']),
+ ("-e py26,py26", ['py26', 'py26']),
+ ("-e py26,py33 -e py33,py27", ['py26', 'py33', 'py33', 'py27'])
+])
+def test_env_spec(cmdline, envlist):
+ args = cmdline.split()
+ config = parseconfig(args)
+ assert config.envlist == envlist
class TestCommandParser:
diff -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 tests/test_interpreters.py
--- a/tests/test_interpreters.py
+++ b/tests/test_interpreters.py
@@ -3,11 +3,13 @@
import pytest
from tox.interpreters import * # noqa
+from tox._config import get_plugin_manager
@pytest.fixture
def interpreters():
- return Interpreters()
+ pm = get_plugin_manager()
+ return Interpreters(hook=pm.hook)
@pytest.mark.skipif("sys.platform != 'win32'")
@@ -28,8 +30,8 @@
assert locate_via_py('3', '2') == sys.executable
-def test_find_executable():
- p = find_executable(sys.executable)
+def test_tox_get_python_executable():
+ p = tox_get_python_executable(sys.executable)
assert p == py.path.local(sys.executable)
for ver in [""] + "2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3".split():
name = "python%s" % ver
@@ -42,7 +44,7 @@
else:
if not py.path.local.sysfind(name):
continue
- p = find_executable(name)
+ p = tox_get_python_executable(name)
assert p
popen = py.std.subprocess.Popen([str(p), '-V'],
stderr=py.std.subprocess.PIPE)
@@ -55,7 +57,7 @@
def sysfind(x):
return "hello"
monkeypatch.setattr(py.path.local, "sysfind", sysfind)
- t = find_executable("qweqwe")
+ t = tox_get_python_executable("qweqwe")
assert t == "hello"
diff -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 tests/test_venv.py
--- a/tests/test_venv.py
+++ b/tests/test_venv.py
@@ -65,7 +65,7 @@
# assert Envconfig.toxworkdir in args
assert venv.getcommandpath("easy_install", cwd=py.path.local())
interp = venv._getliveconfig().python
- assert interp == venv.envconfig._basepython_info.executable
+ assert interp == venv.envconfig.python_info.executable
assert venv.path_config.check(exists=False)
diff -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -22,7 +22,9 @@
deps = pytest-flakes>=0.2
pytest-pep8
-commands = py.test -x --flakes --pep8 tox tests
+commands =
+ py.test --flakes -m flakes tox tests
+ py.test --pep8 -m pep8 tox tests
[testenv:dev]
# required to make looponfail reload on every source code change
diff -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 tox/__init__.py
--- 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 -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 tox/_cmdline.py
--- a/tox/_cmdline.py
+++ b/tox/_cmdline.py
@@ -24,7 +24,7 @@
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 @@
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 -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 tox/_config.py
--- a/tox/_config.py
+++ b/tox/_config.py
@@ -8,8 +8,10 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 tox/_venv.py
--- a/tox/_venv.py
+++ b/tox/_venv.py
@@ -143,7 +143,7 @@
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 -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 tox/hookspecs.py
--- /dev/null
+++ b/tox/hookspecs.py
@@ -0,0 +1,28 @@
+""" Hook specifications for tox.
+
+"""
+
+from pluggy import HookspecMarker, HookimplMarker
+
+hookspec = HookspecMarker("tox")
+hookimpl = HookimplMarker("tox")
+
+
+@hookspec
+def tox_addoption(parser):
+ """ add command line options to the argparse-style parser object."""
+
+
+@hookspec
+def tox_configure(config):
+ """ called after command line options have been parsed and the ini-file has
+ been read. Please be aware that the config object layout may change as its
+ API was not designed yet wrt to providing stability (it was an internal
+ thing purely before tox-2.0). """
+
+
+@hookspec(firstresult=True)
+def tox_get_python_executable(name):
+ """ return a python executable for the given python base name.
+ The first plugin/hook which returns an executable path will determine it.
+ """
diff -r 850fb37c60625112b2bf5ad21373d2804be98336 -r
581c658b9b3978c753213450cce5b8222100d232 tox/interpreters.py
--- a/tox/interpreters.py
+++ b/tox/interpreters.py
@@ -2,12 +2,14 @@
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 @@
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,10 +128,33 @@
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:
+ @hookimpl
+ def tox_get_python_executable(name):
+ p = py.path.local.sysfind(name)
+ if p:
+ return p
+ actual = None
+ # Is this a standard PythonX.Y name?
+ m = re.match(r"python(\d)\.(\d)", name)
+ if m:
+ # The standard names are in predictable places.
+ actual = r"c:\python%s%s\python.exe" % m.groups()
+ if not actual:
+ actual = win32map.get(name, None)
+ if actual:
+ actual = py.path.local(actual)
+ if actual.check():
+ return actual
+ # The standard executables can be found as a last resort via the
+ # Python launcher py.exe
+ if m:
+ return locate_via_py(*m.groups())
+
# Exceptions to the usual windows mapping
win32map = {
'python': sys.executable,
@@ -149,27 +175,6 @@
if exe.check():
return exe
- def find_executable(name):
- p = py.path.local.sysfind(name)
- if p:
- return p
- actual = None
- # Is this a standard PythonX.Y name?
- m = re.match(r"python(\d)\.(\d)", name)
- if m:
- # The standard names are in predictable places.
- actual = r"c:\python%s%s\python.exe" % m.groups()
- if not actual:
- actual = win32map.get(name, None)
- if actual:
- actual = py.path.local(actual)
- if actual.check():
- return actual
- # The standard executables can be found as a last resort via the
- # Python launcher py.exe
- if m:
- return locate_via_py(*m.groups())
-
def pyinfo():
import sys
Repository URL: https://bitbucket.org/hpk42/tox/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
_______________________________________________
pytest-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pytest-commit