summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.pre-commit-config.yaml12
-rw-r--r--README.rst3
-rw-r--r--doc/conf.py66
-rw-r--r--setup.py91
-rw-r--r--tasks/pre-process-changelog.py20
-rw-r--r--tests/conftest.py1
-rw-r--r--tests/test_config.py1374
-rw-r--r--tests/test_interpreters.py51
-rw-r--r--tests/test_pytest_plugins.py116
-rw-r--r--tests/test_quickstart.py153
-rw-r--r--tests/test_result.py25
-rw-r--r--tests/test_venv.py496
-rw-r--r--tests/test_z_cmdline.py714
-rw-r--r--tox.ini4
-rw-r--r--tox/__init__.py24
-rw-r--r--tox/__main__.py2
-rw-r--r--tox/_pytestplugin.py109
-rw-r--r--tox/_quickstart.py191
-rw-r--r--tox/_verlib.py65
-rwxr-xr-xtox/config.py696
-rw-r--r--tox/constants.py76
-rw-r--r--tox/exception.py24
-rw-r--r--tox/interpreters.py60
-rw-r--r--tox/result.py19
-rw-r--r--tox/session.py243
-rwxr-xr-xtox/venv.py175
26 files changed, 2843 insertions, 1967 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 41d395a2..4068a590 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,13 +1,17 @@
repos:
+- repo: https://github.com/ambv/black
+ rev: 18.4a4
+ hooks:
+ - id: black
+ args: [--line-length=99, --safe]
+ python_version: python3.6
- repo: https://github.com/pre-commit/pre-commit-hooks
- sha: v1.1.1
+ rev: v1.2.3
hooks:
- - id: trailing-whitespace
- - id: end-of-file-fixer
- id: check-yaml
- id: debug-statements
- id: flake8
- repo: https://github.com/asottile/pyupgrade
- sha: v1.2.0
+ rev: v1.2.0
hooks:
- id: pyupgrade
diff --git a/README.rst b/README.rst
index c3878abf..70397885 100644
--- a/README.rst
+++ b/README.rst
@@ -16,6 +16,9 @@
.. image:: https://readthedocs.org/projects/tox/badge/?version=latest
:target: http://tox.readthedocs.io/en/latest/?badge=latest
:alt: Documentation status
+.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
+ :target: https://github.com/ambv/black
+ :alt: Code style: black
tox automation project
======================
diff --git a/doc/conf.py b/doc/conf.py
index 29cdef39..da291f63 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -5,57 +5,59 @@ from datetime import date
from pkg_resources import get_distribution
sys.path.insert(0, os.path.dirname(__file__))
-extensions = ['sphinx.ext.autodoc',
- 'sphinx.ext.extlinks',
- 'sphinx.ext.intersphinx',
- 'sphinx.ext.viewcode']
+extensions = [
+ "sphinx.ext.autodoc", "sphinx.ext.extlinks", "sphinx.ext.intersphinx", "sphinx.ext.viewcode"
+]
-project = u'tox'
+project = u"tox"
_full_version = get_distribution(project).version
-release = _full_version.split('+', 1)[0]
-version = '.'.join(release.split('.')[:2])
+release = _full_version.split("+", 1)[0]
+version = ".".join(release.split(".")[:2])
-author = 'holger krekel and others'
+author = "holger krekel and others"
year = date.today().year
-copyright = u'2010-{}, {}'.format(year, author)
+copyright = u"2010-{}, {}".format(year, author)
-master_doc = 'index'
-source_suffix = '.rst'
+master_doc = "index"
+source_suffix = ".rst"
-exclude_patterns = ['_build']
+exclude_patterns = ["_build"]
-templates_path = ['_templates']
-pygments_style = 'sphinx'
-html_theme = 'alabaster'
-html_logo = 'img/tox.png'
-html_favicon = 'img/toxfavi.ico'
-html_static_path = ['_static']
+templates_path = ["_templates"]
+pygments_style = "sphinx"
+html_theme = "alabaster"
+html_logo = "img/tox.png"
+html_favicon = "img/toxfavi.ico"
+html_static_path = ["_static"]
html_show_sourcelink = False
-htmlhelp_basename = '{}doc'.format(project)
-latex_documents = [('index', 'tox.tex', u'{} Documentation'.format(project),
- author, 'manual')]
-man_pages = [('index', project, u'{} Documentation'.format(project),
- [author], 1)]
+htmlhelp_basename = "{}doc".format(project)
+latex_documents = [("index", "tox.tex", u"{} Documentation".format(project), author, "manual")]
+man_pages = [("index", project, u"{} Documentation".format(project), [author], 1)]
epub_title = project
epub_author = author
epub_publisher = author
epub_copyright = copyright
-intersphinx_mapping = {'https://docs.python.org/': None}
+intersphinx_mapping = {"https://docs.python.org/": None}
def setup(app):
# from sphinx.ext.autodoc import cut_lines
# app.connect('autodoc-process-docstring', cut_lines(4, what=['module']))
- app.add_description_unit('confval', 'confval',
- objname='configuration value',
- indextemplate='pair: %s; configuration value')
+ app.add_description_unit(
+ "confval",
+ "confval",
+ objname="configuration value",
+ indextemplate="pair: %s; configuration value",
+ )
-tls_cacerts = os.getenv('SSL_CERT_FILE') # we don't care here about the validity of certificates
+tls_cacerts = os.getenv("SSL_CERT_FILE") # we don't care here about the validity of certificates
linkcheck_timeout = 30
-linkcheck_ignore = [r'http://holgerkrekel.net']
+linkcheck_ignore = [r"http://holgerkrekel.net"]
-extlinks = {'issue': ('https://github.com/tox-dev/tox/issues/%s', '#'),
- 'pull': ('https://github.com/tox-dev/tox/pull/%s', 'p'),
- 'user': ('https://github.com/%s', '@')}
+extlinks = {
+ "issue": ("https://github.com/tox-dev/tox/issues/%s", "#"),
+ "pull": ("https://github.com/tox-dev/tox/pull/%s", "p"),
+ "user": ("https://github.com/%s", "@"),
+}
diff --git a/setup.py b/setup.py
index 4ae2ad0c..d2cb1322 100644
--- a/setup.py
+++ b/setup.py
@@ -17,66 +17,65 @@ def has_environment_marker_support():
* https://www.python.org/dev/peps/pep-0426/#environment-markers
"""
import pkg_resources
+
try:
v = pkg_resources.parse_version(setuptools.__version__)
- return v >= pkg_resources.parse_version('0.7.2')
+ return v >= pkg_resources.parse_version("0.7.2")
except Exception as e:
- sys.stderr.write("Could not test setuptool's version: %s\n" % e)
+ sys.stderr.write("Could not test setuptool's version: {}\n".format(e))
return False
def get_long_description():
- with io.open('README.rst', encoding='utf-8') as f:
- with io.open('CHANGELOG.rst', encoding='utf-8') as g:
- return "%s\n\n%s" % (f.read(), g.read())
+ with io.open("README.rst", encoding="utf-8") as f:
+ with io.open("CHANGELOG.rst", encoding="utf-8") as g:
+ return u"{}\n\n{}".format(f.read(), g.read())
def main():
setuptools.setup(
- name='tox',
- description='virtualenv-based automation of test activities',
+ name="tox",
+ description="virtualenv-based automation of test activities",
long_description=get_long_description(),
- url='https://tox.readthedocs.org/',
+ url="https://tox.readthedocs.org/",
use_scm_version=True,
- license='http://opensource.org/licenses/MIT',
- platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
- author='holger krekel',
- author_email='holger@merlinux.eu',
- packages=['tox'],
- entry_points={'console_scripts': ['tox=tox:cmdline',
- 'tox-quickstart=tox._quickstart:main']},
- python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
- setup_requires=['setuptools_scm'],
- install_requires=['py>=1.4.17',
- 'pluggy>=0.3.0,<1.0',
- 'six',
- 'virtualenv>=1.11.2'],
- extras_require={'testing': ['pytest >= 3.0.0',
- 'pytest-cov',
- 'pytest-mock',
- 'pytest-timeout',
- 'pytest-xdist'],
- 'docs': ['sphinx >= 1.6.3, < 2',
- 'towncrier >= 17.8.0'],
- 'lint': ['flake8 == 3.4.1',
- 'flake8-bugbear == 17.4.0',
- 'pre-commit == 1.4.4'],
- 'publish': ['devpi',
- 'twine']},
- classifiers=['Development Status :: 5 - Production/Stable',
- 'Framework :: tox',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: MIT License',
- 'Operating System :: POSIX',
- 'Operating System :: Microsoft :: Windows',
- 'Operating System :: MacOS :: MacOS X',
- 'Topic :: Software Development :: Testing',
- 'Topic :: Software Development :: Libraries',
- 'Topic :: Utilities'] + [
- ('Programming Language :: Python :: {}'.format(x)) for
- x in '2 2.7 3 3.4 3.5 3.6'.split()]
+ license="http://opensource.org/licenses/MIT",
+ platforms=["unix", "linux", "osx", "cygwin", "win32"],
+ author="holger krekel",
+ author_email="holger@merlinux.eu",
+ packages=["tox"],
+ entry_points={
+ "console_scripts": ["tox=tox:cmdline", "tox-quickstart=tox._quickstart:main"]
+ },
+ python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
+ setup_requires=["setuptools_scm"],
+ install_requires=["py>=1.4.17", "pluggy>=0.3.0,<1.0", "six", "virtualenv>=1.11.2"],
+ extras_require={
+ "testing": [
+ "pytest >= 3.0.0", "pytest-cov", "pytest-mock", "pytest-timeout", "pytest-xdist"
+ ],
+ "docs": ["sphinx >= 1.6.3, < 2", "towncrier >= 17.8.0"],
+ "lint": ["flake8 == 3.5.0", "flake8-bugbear == 18.2.0", "pre-commit == 1.8.2"],
+ "publish": ["devpi", "twine"],
+ },
+ classifiers=[
+ "Development Status :: 5 - Production/Stable",
+ "Framework :: tox",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: MIT License",
+ "Operating System :: POSIX",
+ "Operating System :: Microsoft :: Windows",
+ "Operating System :: MacOS :: MacOS X",
+ "Topic :: Software Development :: Testing",
+ "Topic :: Software Development :: Libraries",
+ "Topic :: Utilities",
+ ]
+ + [
+ ("Programming Language :: Python :: {}".format(x))
+ for x in "2 2.7 3 3.4 3.5 3.6".split()
+ ],
)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/tasks/pre-process-changelog.py b/tasks/pre-process-changelog.py
index 81bcd61a..f77ac170 100644
--- a/tasks/pre-process-changelog.py
+++ b/tasks/pre-process-changelog.py
@@ -17,28 +17,28 @@ def include_draft_newsfragments():
current_path = os.getcwd()
try:
os.chdir(project_root)
- cmd = ['towncrier', '--draft', '--dir', project_root]
- out = subprocess.check_output(cmd).decode('utf-8').strip()
- docs_build_dir = project_root / '.tox' / 'docs' / 'fragments.rst'
+ cmd = ["towncrier", "--draft", "--dir", project_root]
+ out = subprocess.check_output(cmd).decode("utf-8").strip()
+ docs_build_dir = project_root / ".tox" / "docs" / "fragments.rst"
docs_build_dir.write(out)
finally:
os.chdir(current_path)
def manipulate_the_news():
- home = 'https://github.com'
- issue = '%s/issue' % home
- fragmentsPath = Path(__file__).parents[1] / 'tox' / 'changelog'
+ home = "https://github.com"
+ issue = "{}/issue".format(home)
+ fragmentsPath = Path(__file__).parents[1] / "tox" / "changelog"
for pattern, replacement in (
- (r'[^`]@([^,\s]+)', r'`@\1 <%s/\1>`_' % home),
- (r'[^`]#([\d]+)', r'`#pr\1 <%s/\1>`_' % issue),
+ (r"[^`]@([^,\s]+)", r"`@\1 <{}/\1>`_".format(home)),
+ (r"[^`]#([\d]+)", r"`#pr\1 <{}/\1>`_".format(issue)),
):
- for path in fragmentsPath.glob('*.rst'):
+ for path in fragmentsPath.glob("*.rst"):
path.write_text(re.sub(pattern, replacement, path.read_text()))
main = manipulate_the_news
-if __name__ == '__main__':
+if __name__ == "__main__":
sys.exit(main())
diff --git a/tests/conftest.py b/tests/conftest.py
index c3038777..ec59f4a1 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,4 +1,5 @@
# FIXME this seems unnecessary
# TODO move fixtures here and only keep helper functions/classes in the plugin
# TODO _pytest_helpers might be a better name than _pytestplugin then?
+# noinspection PyUnresolvedReferences
from tox._pytestplugin import * # noqa
diff --git a/tests/test_config.py b/tests/test_config.py
index 43f323ba..a81a7ca1 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -9,26 +9,39 @@ from pluggy import PluginManager
import tox
from tox.config import (
- CommandParser, DepOption, SectionReader, get_homedir, get_version_info,
- getcontextname, is_section_substitution, parseconfig)
+ CommandParser,
+ DepOption,
+ SectionReader,
+ get_homedir,
+ get_version_info,
+ getcontextname,
+ is_section_substitution,
+ parseconfig,
+)
from tox.venv import VirtualEnv
class TestVenvConfig:
+
def test_config_parsing_minimal(self, tmpdir, newconfig):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:py1]
- """)
+ """,
+ )
assert len(config.envconfigs) == 1
assert config.toxworkdir.realpath() == tmpdir.join(".tox").realpath()
- assert config.envconfigs['py1'].basepython == sys.executable
- assert config.envconfigs['py1'].deps == []
- assert config.envconfigs['py1'].platform == ".*"
+ assert config.envconfigs["py1"].basepython == sys.executable
+ assert config.envconfigs["py1"].deps == []
+ assert config.envconfigs["py1"].platform == ".*"
def test_config_parsing_multienv(self, tmpdir, newconfig):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[tox]
- toxworkdir = %s
+ toxworkdir = {}
indexserver =
xyz = xyz_repo
[testenv:py1]
@@ -37,43 +50,54 @@ class TestVenvConfig:
deps=
world1
:xyz:http://hello/world
- """ % (tmpdir,))
+ """.format(
+ tmpdir
+ ),
+ )
assert config.toxworkdir == tmpdir
assert len(config.envconfigs) == 2
- assert config.envconfigs['py1'].envdir == tmpdir.join("py1")
- dep = config.envconfigs['py1'].deps[0]
+ assert config.envconfigs["py1"].envdir == tmpdir.join("py1")
+ dep = config.envconfigs["py1"].deps[0]
assert dep.name == "hello"
assert dep.indexserver is None
- assert config.envconfigs['py2'].envdir == tmpdir.join("py2")
- dep1, dep2 = config.envconfigs['py2'].deps
+ assert config.envconfigs["py2"].envdir == tmpdir.join("py2")
+ dep1, dep2 = config.envconfigs["py2"].deps
assert dep1.name == "world1"
assert dep2.name == "http://hello/world"
assert dep2.indexserver.name == "xyz"
assert dep2.indexserver.url == "xyz_repo"
def test_envdir_set_manually(self, tmpdir, newconfig):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:devenv]
envdir = devenv
- """)
- envconfig = config.envconfigs['devenv']
- assert envconfig.envdir == tmpdir.join('devenv')
+ """,
+ )
+ envconfig = config.envconfigs["devenv"]
+ assert envconfig.envdir == tmpdir.join("devenv")
def test_envdir_set_manually_with_substitutions(self, newconfig):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:devenv]
envdir = {toxworkdir}/foobar
- """)
- envconfig = config.envconfigs['devenv']
- assert envconfig.envdir == config.toxworkdir.join('foobar')
+ """,
+ )
+ envconfig = config.envconfigs["devenv"]
+ assert envconfig.envdir == config.toxworkdir.join("foobar")
def test_force_dep_version(self, initproj):
"""
Make sure we can override dependencies configured in tox.ini when using the command line
option --force-dep.
"""
- initproj("example123-0.5", filedefs={
- 'tox.ini': '''
+ initproj(
+ "example123-0.5",
+ filedefs={
+ "tox.ini": """
[tox]
[testenv]
@@ -82,39 +106,39 @@ class TestVenvConfig:
dep2>=2.0
dep3
dep4==4.0
- '''
- })
+ """
+ },
+ )
config = parseconfig(
- ['--force-dep=dep1==1.5', '--force-dep=dep2==2.1',
- '--force-dep=dep3==3.0'])
- assert config.option.force_dep == [
- 'dep1==1.5', 'dep2==2.1', 'dep3==3.0']
- assert [str(x) for x in config.envconfigs['python'].deps] == [
- 'dep1==1.5', 'dep2==2.1', 'dep3==3.0', 'dep4==4.0'
- ]
+ ["--force-dep=dep1==1.5", "--force-dep=dep2==2.1", "--force-dep=dep3==3.0"]
+ )
+ assert config.option.force_dep == ["dep1==1.5", "dep2==2.1", "dep3==3.0"]
+ expected_deps = ["dep1==1.5", "dep2==2.1", "dep3==3.0", "dep4==4.0"]
+ assert expected_deps == [str(x) for x in config.envconfigs["python"].deps]
def test_force_dep_with_url(self, initproj):
- initproj("example123-0.5", filedefs={
- 'tox.ini': '''
+ initproj(
+ "example123-0.5",
+ filedefs={
+ "tox.ini": """
[tox]
[testenv]
deps=
dep1==1.0
https://pypi.org/xyz/pkg1.tar.gz
- '''
- })
- config = parseconfig(
- ['--force-dep=dep1==1.5'])
- assert config.option.force_dep == [
- 'dep1==1.5'
- ]
- assert [str(x) for x in config.envconfigs['python'].deps] == [
- 'dep1==1.5', 'https://pypi.org/xyz/pkg1.tar.gz'
- ]
+ """
+ },
+ )
+ config = parseconfig(["--force-dep=dep1==1.5"])
+ assert config.option.force_dep == ["dep1==1.5"]
+ expected_deps = ["dep1==1.5", "https://pypi.org/xyz/pkg1.tar.gz"]
+ assert [str(x) for x in config.envconfigs["python"].deps] == expected_deps
def test_process_deps(self, newconfig):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv]
deps =
-r requirements.txt
@@ -123,41 +147,53 @@ class TestVenvConfig:
--global-option=foo
-v dep1
--help dep2
- """) # note that those last two are invalid
- assert [str(x) for x in config.envconfigs['python'].deps] == [
- '-rrequirements.txt', '--index-url=https://pypi.org/simple',
- '-fhttps://pypi.org/packages', '--global-option=foo',
- '-v dep1', '--help dep2'
+ """,
+ ) # note that those last two are invalid
+ expected_deps = [
+ "-rrequirements.txt",
+ "--index-url=https://pypi.org/simple",
+ "-fhttps://pypi.org/packages",
+ "--global-option=foo",
+ "-v dep1",
+ "--help dep2",
]
+ assert [str(x) for x in config.envconfigs["python"].deps] == expected_deps
def test_is_same_dep(self):
"""
Ensure correct parseini._is_same_dep is working with a few samples.
"""
- assert DepOption._is_same_dep('pkg_hello-world3==1.0', 'pkg_hello-world3')
- assert DepOption._is_same_dep('pkg_hello-world3==1.0', 'pkg_hello-world3>=2.0')
- assert DepOption._is_same_dep('pkg_hello-world3==1.0', 'pkg_hello-world3>2.0')
- assert DepOption._is_same_dep('pkg_hello-world3==1.0', 'pkg_hello-world3<2.0')
- assert DepOption._is_same_dep('pkg_hello-world3==1.0', 'pkg_hello-world3<=2.0')
- assert not DepOption._is_same_dep('pkg_hello-world3==1.0', 'otherpkg>=2.0')
+ assert DepOption._is_same_dep("pkg_hello-world3==1.0", "pkg_hello-world3")
+ assert DepOption._is_same_dep("pkg_hello-world3==1.0", "pkg_hello-world3>=2.0")
+ assert DepOption._is_same_dep("pkg_hello-world3==1.0", "pkg_hello-world3>2.0")
+ assert DepOption._is_same_dep("pkg_hello-world3==1.0", "pkg_hello-world3<2.0")
+ assert DepOption._is_same_dep("pkg_hello-world3==1.0", "pkg_hello-world3<=2.0")
+ assert not DepOption._is_same_dep("pkg_hello-world3==1.0", "otherpkg>=2.0")
class TestConfigPlatform:
+
def test_config_parse_platform(self, newconfig):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:py1]
platform = linux2
- """)
+ """,
+ )
assert len(config.envconfigs) == 1
- assert config.envconfigs['py1'].platform == "linux2"
+ assert config.envconfigs["py1"].platform == "linux2"
def test_config_parse_platform_rex(self, newconfig, mocksession, monkeypatch):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:py1]
platform = a123|b123
- """)
+ """,
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['py1']
+ envconfig = config.envconfigs["py1"]
venv = VirtualEnv(envconfig, session=mocksession)
assert not venv.matching_platform()
monkeypatch.setattr(sys, "platform", "a123")
@@ -169,26 +205,30 @@ class TestConfigPlatform:
@pytest.mark.parametrize("plat", ["win", "lin", "osx"])
def test_config_parse_platform_with_factors(self, newconfig, plat):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[tox]
envlist = py27-{win, lin,osx }
[testenv]
platform =
win: win32
lin: linux2
- """)
+ """,
+ )
assert len(config.envconfigs) == 3
- platform = config.envconfigs['py27-' + plat].platform
+ platform = config.envconfigs["py27-" + plat].platform
expected = {"win": "win32", "lin": "linux2", "osx": ""}.get(plat)
assert platform == expected
class TestConfigPackage:
+
def test_defaults(self, tmpdir, newconfig):
config = newconfig([], "")
assert config.setupdir.realpath() == tmpdir.realpath()
assert config.toxworkdir.realpath() == tmpdir.join(".tox").realpath()
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
assert envconfig.args_are_paths
assert not envconfig.recreate
assert not envconfig.pip_pre
@@ -204,14 +244,19 @@ class TestConfigPackage:
assert config.toxworkdir.realpath() == tmpdir.join(".tox").realpath()
def test_project_paths(self, tmpdir, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[tox]
- toxworkdir=%s
- """ % tmpdir)
+ toxworkdir={}
+ """.format(
+ tmpdir
+ )
+ )
assert config.toxworkdir == tmpdir
class TestParseconfig:
+
def test_search_parents(self, tmpdir):
b = tmpdir.mkdir("a").mkdir("b")
toxinipath = tmpdir.ensure("tox.ini")
@@ -226,31 +271,29 @@ class TestParseconfig:
"""
Test explicitly setting config path, both with and without the filename
"""
- path = tmpdir.mkdir('tox_tmp_directory')
- config_file_path = path.ensure('tox.ini')
+ path = tmpdir.mkdir("tox_tmp_directory")
+ config_file_path = path.ensure("tox.ini")
- config = parseconfig(['-c', str(config_file_path)])
+ config = parseconfig(["-c", str(config_file_path)])
assert config.toxinipath == config_file_path
# Passing directory of the config file should also be possible
# ('tox.ini' filename is assumed)
- config = parseconfig(['-c', str(path)])
+ config = parseconfig(["-c", str(path)])
assert config.toxinipath == config_file_path
def test_get_homedir(monkeypatch):
- monkeypatch.setattr(py.path.local, "_gethomedir",
- classmethod(lambda x: {}[1]))
+ monkeypatch.setattr(py.path.local, "_gethomedir", classmethod(lambda x: {}[1]))
assert not get_homedir()
- monkeypatch.setattr(py.path.local, "_gethomedir",
- classmethod(lambda x: 0 / 0))
+ monkeypatch.setattr(py.path.local, "_gethomedir", classmethod(lambda x: 0 / 0))
assert not get_homedir()
- monkeypatch.setattr(py.path.local, "_gethomedir",
- classmethod(lambda x: "123"))
+ monkeypatch.setattr(py.path.local, "_gethomedir", classmethod(lambda x: "123"))
assert get_homedir() == "123"
class TestGetcontextname:
+
def test_blank(self, monkeypatch):
monkeypatch.setattr(os, "environ", {})
assert getcontextname() is None
@@ -268,13 +311,15 @@ class TestIniParserAgainstCommandsKey:
"""Test parsing commands with substitutions"""
def test_command_substitution_from_other_section(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key = whatever
[testenv]
commands =
echo {[section]key}
- """)
+ """
+ )
reader = SectionReader("testenv", config._cfg)
x = reader.getargvlist("commands")
assert x == [["echo", "whatever"]]
@@ -282,7 +327,8 @@ class TestIniParserAgainstCommandsKey:
def test_command_substitution_from_other_section_multiline(self, newconfig):
"""Ensure referenced multiline commands form from other section injected
as multiple commands."""
- config = newconfig("""
+ config = newconfig(
+ """
[section]
commands =
cmd1 param11 param12
@@ -299,70 +345,81 @@ class TestIniParserAgainstCommandsKey:
{[section]commands}
# comment is omitted
echo {[base]commands}
- """)
+ """
+ )
reader = SectionReader("testenv", config._cfg)
x = reader.getargvlist("commands")
- assert x == [
+ expected_deps = [
"cmd1 param11 param12".split(),
"cmd2 param21 param22".split(),
"cmd1 param11 param12".split(),
"cmd2 param21 param22".split(),
- ["echo", "cmd", "1", "2", "3", "4", "cmd", "2"]
+ ["echo", "cmd", "1", "2", "3", "4", "cmd", "2"],
]
+ assert x == expected_deps
def test_command_substitution_from_other_section_posargs(self, newconfig):
"""Ensure subsitition from other section with posargs succeeds"""
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key = thing {posargs} arg2
[testenv]
commands =
{[section]key}
- """)
+ """
+ )
reader = SectionReader("testenv", config._cfg)
reader.addsubstitutions([r"argpos"])
x = reader.getargvlist("commands")
- assert x == [['thing', 'argpos', 'arg2']]
+ assert x == [["thing", "argpos", "arg2"]]
def test_command_section_and_posargs_substitution(self, newconfig):
"""Ensure subsitition from other section with posargs succeeds"""
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key = thing arg1
[testenv]
commands =
{[section]key} {posargs} endarg
- """)
+ """
+ )
reader = SectionReader("testenv", config._cfg)
reader.addsubstitutions([r"argpos"])
x = reader.getargvlist("commands")
- assert x == [['thing', 'arg1', 'argpos', 'endarg']]
+ assert x == [["thing", "arg1", "argpos", "endarg"]]
def test_command_env_substitution(self, newconfig):
"""Ensure referenced {env:key:default} values are substituted correctly."""
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:py27]
setenv =
TEST=testvalue
commands =
ls {env:TEST}
- """)
+ """
+ )
envconfig = config.envconfigs["py27"]
assert envconfig.commands == [["ls", "testvalue"]]
assert envconfig.setenv["TEST"] == "testvalue"
def test_command_env_substitution_global(self, newconfig):
"""Ensure referenced {env:key:default} values are substituted correctly."""
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
setenv = FOO = bar
commands = echo {env:FOO}
- """)
- envconfig = config.envconfigs['python']
+ """
+ )
+ envconfig = config.envconfigs["python"]
assert envconfig.commands == [["echo", "bar"]]
def test_regression_issue595(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[tox]
envlist = foo
[testenv]
@@ -371,18 +428,22 @@ class TestIniParserAgainstCommandsKey:
setenv = {[testenv]setenv}
[testenv:baz]
setenv =
- """)
- assert config.envconfigs['foo'].setenv['VAR'] == 'x'
- assert config.envconfigs['bar'].setenv['VAR'] == 'x'
- assert 'VAR' not in config.envconfigs['baz'].setenv
+ """
+ )
+ assert config.envconfigs["foo"].setenv["VAR"] == "x"
+ assert config.envconfigs["bar"].setenv["VAR"] == "x"
+ assert "VAR" not in config.envconfigs["baz"].setenv
class TestIniParser:
+
def test_getstring_single(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key=value
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
x = reader.getstring("key")
assert x == "value"
@@ -391,23 +452,27 @@ class TestIniParser:
assert x == "world"
def test_missing_substitution(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[mydefault]
key2={xyz}
- """)
- reader = SectionReader("mydefault", config._cfg, fallbacksections=['mydefault'])
+ """
+ )
+ reader = SectionReader("mydefault", config._cfg, fallbacksections=["mydefault"])
assert reader is not None
with pytest.raises(tox.exception.ConfigError):
reader.getstring("key2")
def test_getstring_fallback_sections(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[mydefault]
key2=value2
[section]
key=value
- """)
- reader = SectionReader("section", config._cfg, fallbacksections=['mydefault'])
+ """
+ )
+ reader = SectionReader("section", config._cfg, fallbacksections=["mydefault"])
x = reader.getstring("key2")
assert x == "value2"
x = reader.getstring("key3")
@@ -416,13 +481,15 @@ class TestIniParser:
assert x == "world"
def test_getstring_substitution(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[mydefault]
key2={value2}
[section]
key={value}
- """)
- reader = SectionReader("section", config._cfg, fallbacksections=['mydefault'])
+ """
+ )
+ reader = SectionReader("section", config._cfg, fallbacksections=["mydefault"])
reader.addsubstitutions(value="newvalue", value2="newvalue2")
x = reader.getstring("key2")
assert x == "newvalue2"
@@ -432,31 +499,35 @@ class TestIniParser:
assert x == "newvalue2"
def test_getlist(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key2=
item1
{item2}
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
reader.addsubstitutions(item1="not", item2="grr")
x = reader.getlist("key2")
- assert x == ['item1', 'grr']
+ assert x == ["item1", "grr"]
def test_getdict(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key2=
key1=item1
key2={item2}
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
reader.addsubstitutions(item1="not", item2="grr")
x = reader.getdict("key2")
- assert 'key1' in x
- assert 'key2' in x
- assert x['key1'] == 'item1'
- assert x['key2'] == 'grr'
+ assert "key1" in x
+ assert "key2" in x
+ assert x["key1"] == "item1"
+ assert x["key2"] == "grr"
x = reader.getdict("key3", {1: 2})
assert x == {1: 2}
@@ -474,16 +545,18 @@ class TestIniParser:
def test_missing_env_sub_populates_missing_subs(self, newconfig):
config = newconfig("[testenv:foo]\ncommands={env:VAR}")
print(SectionReader("section", config._cfg).getstring("commands"))
- assert config.envconfigs['foo'].missing_subs == ['VAR']
+ assert config.envconfigs["foo"].missing_subs == ["VAR"]
def test_getstring_environment_substitution_with_default(self, monkeypatch, newconfig):
monkeypatch.setenv("KEY1", "hello")
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key1={env:KEY1:DEFAULT_VALUE}
key2={env:KEY2:DEFAULT_VALUE}
key3={env:KEY3:}
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
x = reader.getstring("key1")
assert x == "hello"
@@ -501,164 +574,188 @@ class TestIniParser:
assert is_section_substitution("{[setup] commands}") is None
def test_getstring_other_section_substitution(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key = rue
[testenv]
key = t{[section]key}
- """)
+ """
+ )
reader = SectionReader("testenv", config._cfg)
x = reader.getstring("key")
assert x == "true"
def test_argvlist(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key2=
cmd1 {item1} {item2}
cmd2 {item2}
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
reader.addsubstitutions(item1="with space", item2="grr")
- assert reader.getargvlist('key1') == []
+ assert reader.getargvlist("key1") == []
x = reader.getargvlist("key2")
- assert x == [["cmd1", "with", "space", "grr"],
- ["cmd2", "grr"]]
+ assert x == [["cmd1", "with", "space", "grr"], ["cmd2", "grr"]]
def test_argvlist_windows_escaping(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
comm = pytest {posargs}
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
reader.addsubstitutions([r"hello\this"])
argv = reader.getargv("comm")
assert argv == ["pytest", "hello\\this"]
def test_argvlist_multiline(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key2=
cmd1 {item1} \
{item2}
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
reader.addsubstitutions(item1="with space", item2="grr")
- assert reader.getargvlist('key1') == []
+ assert reader.getargvlist("key1") == []
x = reader.getargvlist("key2")
assert x == [["cmd1", "with", "space", "grr"]]
def test_argvlist_quoting_in_command(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key1=
cmd1 'part one' \
'part two'
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
x = reader.getargvlist("key1")
assert x == [["cmd1", "part one", "part two"]]
def test_argvlist_comment_after_command(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key1=
cmd1 --flag # run the flag on the command
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
x = reader.getargvlist("key1")
assert x == [["cmd1", "--flag"]]
def test_argvlist_command_contains_hash(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key1=
cmd1 --re "use the # symbol for an arg"
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
x = reader.getargvlist("key1")
assert x == [["cmd1", "--re", "use the # symbol for an arg"]]
def test_argvlist_positional_substitution(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key2=
cmd1 []
cmd2 {posargs:{item2} \
other}
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
- posargs = ['hello', 'world']
+ posargs = ["hello", "world"]
reader.addsubstitutions(posargs, item2="value2")
- assert reader.getargvlist('key1') == []
+ assert reader.getargvlist("key1") == []
argvlist = reader.getargvlist("key2")
assert argvlist[0] == ["cmd1"] + posargs
assert argvlist[1] == ["cmd2"] + posargs
reader = SectionReader("section", config._cfg)
reader.addsubstitutions([], item2="value2")
- assert reader.getargvlist('key1') == []
+ assert reader.getargvlist("key1") == []
argvlist = reader.getargvlist("key2")
assert argvlist[0] == ["cmd1"]
assert argvlist[1] == ["cmd2", "value2", "other"]
def test_argvlist_quoted_posargs(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key2=
cmd1 --foo-args='{posargs}'
cmd2 -f '{posargs}'
cmd3 -f {posargs}
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
reader.addsubstitutions(["foo", "bar"])
- assert reader.getargvlist('key1') == []
+ assert reader.getargvlist("key1") == []
x = reader.getargvlist("key2")
- assert x == [["cmd1", "--foo-args=foo bar"],
- ["cmd2", "-f", "foo bar"],
- ["cmd3", "-f", "foo", "bar"]]
+ expected_deps = [
+ ["cmd1", "--foo-args=foo bar"], ["cmd2", "-f", "foo bar"], ["cmd3", "-f", "foo", "bar"]
+ ]
+ assert x == expected_deps
def test_argvlist_posargs_with_quotes(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key2=
cmd1 -f {posargs}
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
reader.addsubstitutions(["foo", "'bar", "baz'"])
- assert reader.getargvlist('key1') == []
+ assert reader.getargvlist("key1") == []
x = reader.getargvlist("key2")
assert x == [["cmd1", "-f", "foo", "bar baz"]]
def test_positional_arguments_are_only_replaced_when_standing_alone(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key=
cmd0 []
cmd1 -m '[abc]'
cmd2 -m '\'something\'' []
cmd3 something[]else
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
- posargs = ['hello', 'world']
+ posargs = ["hello", "world"]
reader.addsubstitutions(posargs)
- argvlist = reader.getargvlist('key')
- assert argvlist[0] == ['cmd0'] + posargs
- assert argvlist[1] == ['cmd1', '-m', '[abc]']
- assert argvlist[2] == ['cmd2', '-m', "something"] + posargs
- assert argvlist[3] == ['cmd3', 'something[]else']
+ argvlist = reader.getargvlist("key")
+ assert argvlist[0] == ["cmd0"] + posargs
+ assert argvlist[1] == ["cmd1", "-m", "[abc]"]
+ assert argvlist[2] == ["cmd2", "-m", "something"] + posargs
+ assert argvlist[3] == ["cmd3", "something[]else"]
def test_posargs_are_added_escaped_issue310(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key= cmd0 {posargs}
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
- posargs = ['hello world', '--x==y z', '--format=%(code)s: %(text)s']
+ posargs = ["hello world", "--x==y z", "--format=%(code)s: %(text)s"]
reader.addsubstitutions(posargs)
- argvlist = reader.getargvlist('key')
- assert argvlist[0] == ['cmd0'] + posargs
+ argvlist = reader.getargvlist("key")
+ assert argvlist[0] == ["cmd0"] + posargs
def test_substitution_with_multiple_words(self, newconfig):
inisource = """
@@ -667,42 +764,46 @@ class TestIniParser:
"""
config = newconfig(inisource)
reader = SectionReader("section", config._cfg)
- posargs = ['hello', 'world']
- reader.addsubstitutions(posargs, envlogdir='ENV_LOG_DIR', envname='ENV_NAME')
+ posargs = ["hello", "world"]
+ reader.addsubstitutions(posargs, envlogdir="ENV_LOG_DIR", envname="ENV_NAME")
- expected = [
- 'pytest', '-n5', '--junitxml=ENV_LOG_DIR/junit-ENV_NAME.xml', 'hello', 'world'
- ]
- assert reader.getargvlist('key')[0] == expected
+ expected = ["pytest", "-n5", "--junitxml=ENV_LOG_DIR/junit-ENV_NAME.xml", "hello", "world"]
+ assert reader.getargvlist("key")[0] == expected
def test_getargv(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key=some command "with quoting"
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
- expected = ['some', 'command', 'with quoting']
- assert reader.getargv('key') == expected
+ expected = ["some", "command", "with quoting"]
+ assert reader.getargv("key") == expected
def test_getpath(self, tmpdir, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
path1={HELLO}
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
reader.addsubstitutions(toxinidir=tmpdir, HELLO="mypath")
x = reader.getpath("path1", tmpdir)
assert x == tmpdir.join("mypath")
def test_getbool(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[section]
key1=True
key2=False
key1a=true
key2a=falsE
key5=yes
- """)
+ """
+ )
reader = SectionReader("section", config._cfg)
assert reader.getbool("key1") is True
assert reader.getbool("key1a") is True
@@ -715,11 +816,14 @@ class TestIniParser:
class TestIniParserPrefix:
+
def test_basic_section_access(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[p:section]
key=value
- """)
+ """
+ )
reader = SectionReader("section", config._cfg, prefix="p")
x = reader.getstring("key")
assert x == "value"
@@ -728,14 +832,17 @@ class TestIniParserPrefix:
assert x == "world"
def test_fallback_sections(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[p:mydefault]
key2=value2
[p:section]
key=value
- """)
- reader = SectionReader("section", config._cfg, prefix="p",
- fallbacksections=['p:mydefault'])
+ """
+ )
+ reader = SectionReader(
+ "section", config._cfg, prefix="p", fallbacksections=["p:mydefault"]
+ )
x = reader.getstring("key2")
assert x == "value2"
x = reader.getstring("key3")
@@ -752,45 +859,52 @@ class TestIniParserPrefix:
assert is_section_substitution("{[p:setup] commands}") is None
def test_other_section_substitution(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[p:section]
key = rue
[p:testenv]
key = t{[p:section]key}
- """)
+ """
+ )
reader = SectionReader("testenv", config._cfg, prefix="p")
x = reader.getstring("key")
assert x == "true"
class TestConfigTestEnv:
+
def test_commentchars_issue33(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv] # hello
deps = http://abc#123
commands=
python -c "x ; y"
- """)
+ """
+ )
envconfig = config.envconfigs["python"]
assert envconfig.deps[0].name == "http://abc#123"
assert envconfig.commands[0] == ["python", "-c", "x ; y"]
def test_defaults(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
commands=
xyz --abc
- """)
+ """
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
assert envconfig.commands == [["xyz", "--abc"]]
assert envconfig.changedir == config.setupdir
assert envconfig.sitepackages is False
assert envconfig.usedevelop is False
assert envconfig.ignore_errors is False
assert envconfig.envlogdir == envconfig.envdir.join("log")
- assert list(envconfig.setenv.definitions.keys()) == ['PYTHONHASHSEED']
- hashseed = envconfig.setenv['PYTHONHASHSEED']
+ assert list(envconfig.setenv.definitions.keys()) == ["PYTHONHASHSEED"]
+ hashseed = envconfig.setenv["PYTHONHASHSEED"]
assert isinstance(hashseed, str)
# The following line checks that hashseed parses to an integer.
int_hashseed = int(hashseed)
@@ -800,29 +914,35 @@ class TestConfigTestEnv:
def test_sitepackages_switch(self, newconfig):
config = newconfig(["--sitepackages"], "")
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
assert envconfig.sitepackages is True
def test_installpkg_tops_develop(self, newconfig):
- config = newconfig(["--installpkg=abc"], """
+ config = newconfig(
+ ["--installpkg=abc"],
+ """
[testenv]
usedevelop = True
- """)
+ """,
+ )
assert not config.envconfigs["python"].usedevelop
def test_specific_command_overrides(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
commands=xyz
[testenv:py]
commands=abc
- """)
+ """
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['py']
+ envconfig = config.envconfigs["py"]
assert envconfig.commands == [["abc"]]
def test_whitelist_externals(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
whitelist_externals = xyz
commands=xyz
@@ -831,50 +951,61 @@ class TestConfigTestEnv:
[testenv:py]
whitelist_externals = xyz2
commands=abc
- """)
+ """
+ )
assert len(config.envconfigs) == 2
- envconfig = config.envconfigs['py']
+ envconfig = config.envconfigs["py"]
assert envconfig.commands == [["abc"]]
assert envconfig.whitelist_externals == ["xyz2"]
- envconfig = config.envconfigs['x']
+ envconfig = config.envconfigs["x"]
assert envconfig.whitelist_externals == ["xyz"]
def test_changedir(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
changedir=xyz
- """)
+ """
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
assert envconfig.changedir.basename == "xyz"
assert envconfig.changedir == config.toxinidir.join("xyz")
def test_ignore_errors(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
ignore_errors=True
- """)
+ """
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
assert envconfig.ignore_errors is True
def test_envbindir(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
basepython=python
- """)
+ """
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
assert envconfig.envpython == envconfig.envbindir.join("python")
@pytest.mark.parametrize("bp", ["jython", "pypy", "pypy3"])
def test_envbindir_jython(self, newconfig, bp):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
- basepython=%s
- """ % bp)
+ basepython={}
+ """.format(
+ bp
+ )
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
# on win32 and linux virtualenv uses "bin" for pypy/jython
assert envconfig.envbindir.basename == "bin"
if bp == "jython":
@@ -882,19 +1013,21 @@ class TestConfigTestEnv:
@pytest.mark.parametrize("plat", ["win32", "linux2"])
def test_passenv_as_multiline_list(self, newconfig, monkeypatch, plat):
- monkeypatch.setattr(tox.INFO, 'IS_WIN', plat == 'win32')
+ monkeypatch.setattr(tox.INFO, "IS_WIN", plat == "win32")
monkeypatch.setenv("A123A", "a")
monkeypatch.setenv("A123B", "b")
monkeypatch.setenv("BX23", "0")
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
passenv =
A123*
# isolated comment
B?23
- """)
+ """
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
if plat == "win32":
assert "PATHEXT" in envconfig.passenv
assert "SYSTEMDRIVE" in envconfig.passenv
@@ -918,18 +1051,20 @@ class TestConfigTestEnv:
@pytest.mark.parametrize("plat", ["win32", "linux2"])
def test_passenv_as_space_separated_list(self, newconfig, monkeypatch, plat):
- monkeypatch.setattr(tox.INFO, 'IS_WIN', plat == 'win32')
+ monkeypatch.setattr(tox.INFO, "IS_WIN", plat == "win32")
monkeypatch.setenv("A123A", "a")
monkeypatch.setenv("A123B", "b")
monkeypatch.setenv("BX23", "0")
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
passenv =
# comment
A123* B?23
- """)
+ """
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
if plat == "win32":
assert "PATHEXT" in envconfig.passenv
assert "SYSTEMDRIVE" in envconfig.passenv
@@ -953,7 +1088,8 @@ class TestConfigTestEnv:
monkeypatch.setenv("BX23", "0")
monkeypatch.setenv("CCA43", "3")
monkeypatch.setenv("CB21", "4")
- config = newconfig("""
+ config = newconfig(
+ """
[tox]
envlist = {x1,x2}
[testenv]
@@ -963,7 +1099,8 @@ class TestConfigTestEnv:
# passed to both environments
A123C
x2: A123B A123D
- """)
+ """
+ )
assert len(config.envconfigs) == 2
assert "A123A" in config.envconfigs["x1"].passenv
@@ -986,10 +1123,12 @@ class TestConfigTestEnv:
monkeypatch.setenv("A1", "a1")
monkeypatch.setenv("A2", "a2")
monkeypatch.setenv("TOX_TESTENV_PASSENV", "A1")
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
passenv = A2
- """)
+ """
+ )
env = config.envconfigs["python"]
assert "A1" in env.passenv
assert "A2" in env.passenv
@@ -998,75 +1137,92 @@ class TestConfigTestEnv:
monkeypatch.setenv("A1", "a1")
monkeypatch.setenv("A2", "a2")
monkeypatch.setenv("TOX_TESTENV_PASSENV", "A*")
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
- """)
+ """
+ )
env = config.envconfigs["python"]
assert "A1" in env.passenv
assert "A2" in env.passenv
def test_changedir_override(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
changedir=xyz
[testenv:python]
changedir=abc
basepython=python3.6
- """)
+ """
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
assert envconfig.changedir.basename == "abc"
assert envconfig.changedir == config.setupdir.join("abc")
def test_install_command_setting(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
install_command=some_install {packages}
- """)
- envconfig = config.envconfigs['python']
- assert envconfig.install_command == [
- 'some_install', '{packages}']
+ """
+ )
+ envconfig = config.envconfigs["python"]
+ assert envconfig.install_command == ["some_install", "{packages}"]
def test_install_command_must_contain_packages(self, newconfig):
with pytest.raises(tox.exception.ConfigError):
newconfig("[testenv]\ninstall_command=pip install")
def test_install_command_substitutions(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
install_command=some_install --arg={toxinidir}/foo \
{envname} {opts} {packages}
- """)
- envconfig = config.envconfigs['python']
- assert envconfig.install_command == [
- 'some_install', '--arg=%s/foo' % config.toxinidir, 'python',
- '{opts}', '{packages}']
+ """
+ )
+ envconfig = config.envconfigs["python"]
+ expected_deps = [
+ "some_install",
+ "--arg={}/foo".format(config.toxinidir),
+ "python",
+ "{opts}",
+ "{packages}",
+ ]
+ assert envconfig.install_command == expected_deps
def test_pip_pre(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
pip_pre=true
- """)
- envconfig = config.envconfigs['python']
+ """
+ )
+ envconfig = config.envconfigs["python"]
assert envconfig.pip_pre
def test_pip_pre_cmdline_override(self, newconfig):
config = newconfig(
- ['--pre'],
+ ["--pre"],
"""
[testenv]
pip_pre=false
- """)
- envconfig = config.envconfigs['python']
+ """,
+ )
+ envconfig = config.envconfigs["python"]
assert envconfig.pip_pre
def test_simple(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:py36]
basepython=python3.6
[testenv:py27]
basepython=python2.7
- """)
+ """
+ )
assert len(config.envconfigs) == 2
assert "py36" in config.envconfigs
assert "py27" in config.envconfigs
@@ -1076,7 +1232,8 @@ class TestConfigTestEnv:
newconfig("[testenv:py27]\nbasepython={xyz}")
def test_substitution_defaults(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:py27]
commands =
{toxinidir}
@@ -1088,8 +1245,9 @@ class TestConfigTestEnv:
{homedir}
{distshare}
{envlogdir}
- """)
- conf = config.envconfigs['py27']
+ """
+ )
+ conf = config.envconfigs["py27"]
argv = conf.commands
assert argv[0][0] == config.toxinidir
assert argv[1][0] == config.toxworkdir
@@ -1102,19 +1260,22 @@ class TestConfigTestEnv:
assert argv[8][0] == conf.envlogdir
def test_substitution_notfound_issue246(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:py27]
setenv =
FOO={envbindir}
BAR={envsitepackagesdir}
- """)
- conf = config.envconfigs['py27']
+ """
+ )
+ conf = config.envconfigs["py27"]
env = conf.setenv
- assert 'FOO' in env
- assert 'BAR' in env
+ assert "FOO" in env
+ assert "BAR" in env
def test_substitution_notfound_issue515(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[tox]
envlist = standard-greeting
@@ -1127,16 +1288,16 @@ class TestConfigTestEnv:
NAME
commands =
python -c 'print("Hello, {env:NAME}!")'
- """)
- conf = config.envconfigs['standard-greeting']
- assert conf.commands == [
- ['python', '-c', 'print("Hello, world!")']
- ]
+ """
+ )
+ conf = config.envconfigs["standard-greeting"]
+ assert conf.commands == [["python", "-c", 'print("Hello, world!")']]
def test_substitution_nested_env_defaults(self, newconfig, monkeypatch):
monkeypatch.setenv("IGNORE_STATIC_DEFAULT", "env")
monkeypatch.setenv("IGNORE_DYNAMIC_DEFAULT", "env")
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:py27]
passenv =
IGNORE_STATIC_DEFAULT
@@ -1151,15 +1312,16 @@ class TestConfigTestEnv:
USE_DYNAMIC_DEFAULT={env:USE_DYNAMIC_DEFAULT:{env:OTHER_VAR}+default}
IGNORE_OTHER_DEFAULT={env:OTHER_VAR:{env:OTHER_VAR}+default}
USE_OTHER_DEFAULT={env:NON_EXISTENT_VAR:{env:OTHER_VAR}+default}
- """)
- conf = config.envconfigs['py27']
+ """
+ )
+ conf = config.envconfigs["py27"]
env = conf.setenv
- assert env['IGNORE_STATIC_DEFAULT'] == "env"
- assert env['USE_STATIC_DEFAULT'] == "default"
- assert env['IGNORE_OTHER_DEFAULT'] == "other"
- assert env['USE_OTHER_DEFAULT'] == "other+default"
- assert env['IGNORE_DYNAMIC_DEFAULT'] == "env"
- assert env['USE_DYNAMIC_DEFAULT'] == "other+default"
+ assert env["IGNORE_STATIC_DEFAULT"] == "env"
+ assert env["USE_STATIC_DEFAULT"] == "default"
+ assert env["IGNORE_OTHER_DEFAULT"] == "other"
+ assert env["USE_OTHER_DEFAULT"] == "other+default"
+ assert env["IGNORE_DYNAMIC_DEFAULT"] == "env"
+ assert env["USE_DYNAMIC_DEFAULT"] == "other+default"
def test_substitution_positional(self, newconfig):
inisource = """
@@ -1170,11 +1332,11 @@ class TestConfigTestEnv:
cmd1 {posargs:hello} \
world
"""
- conf = newconfig([], inisource).envconfigs['py27']
+ conf = newconfig([], inisource).envconfigs["py27"]
argv = conf.commands
assert argv[0] == ["cmd1", "[hello]", "world"]
assert argv[1] == ["cmd1", "hello", "world"]
- conf = newconfig(['brave', 'new'], inisource).envconfigs['py27']
+ conf = newconfig(["brave", "new"], inisource).envconfigs["py27"]
argv = conf.commands
assert argv[0] == ["cmd1", "[hello]", "world"]
assert argv[1] == ["cmd1", "brave", "new", "world"]
@@ -1184,7 +1346,7 @@ class TestConfigTestEnv:
[testenv]
commands = echo {posargs:foo}
"""
- conf = newconfig([""], inisource).envconfigs['python']
+ conf = newconfig([""], inisource).envconfigs["python"]
argv = conf.commands
assert argv[0] == ["echo"]
@@ -1198,9 +1360,9 @@ class TestConfigTestEnv:
commands =
echo {{[params]foo2}}
"""
- conf = newconfig([], inisource).envconfigs['py27']
+ conf = newconfig([], inisource).envconfigs["py27"]
argv = conf.commands
- assert argv[0] == ['echo', 'bah']
+ assert argv[0] == ["echo", "bah"]
def test_posargs_backslashed_or_quoted(self, newconfig):
inisource = r"""
@@ -1209,15 +1371,15 @@ class TestConfigTestEnv:
echo "\{posargs\}" = {posargs}
echo "posargs = " "{posargs}"
"""
- conf = newconfig([], inisource).envconfigs['py27']
+ conf = newconfig([], inisource).envconfigs["py27"]
argv = conf.commands
- assert argv[0] == ['echo', '{posargs}', '=']
- assert argv[1] == ['echo', 'posargs = ', ""]
+ assert argv[0] == ["echo", "{posargs}", "="]
+ assert argv[1] == ["echo", "posargs = ", ""]
- conf = newconfig(['dog', 'cat'], inisource).envconfigs['py27']
+ conf = newconfig(["dog", "cat"], inisource).envconfigs["py27"]
argv = conf.commands
- assert argv[0] == ['echo', '{posargs}', '=', 'dog', 'cat']
- assert argv[1] == ['echo', 'posargs = ', 'dog cat']
+ assert argv[0] == ["echo", "{posargs}", "=", "dog", "cat"]
+ assert argv[1] == ["echo", "posargs = ", "dog cat"]
def test_rewrite_posargs(self, tmpdir, newconfig):
inisource = """
@@ -1226,16 +1388,16 @@ class TestConfigTestEnv:
changedir = tests
commands = cmd1 {posargs:hello}
"""
- conf = newconfig([], inisource).envconfigs['py27']
+ conf = newconfig([], inisource).envconfigs["py27"]
argv = conf.commands
assert argv[0] == ["cmd1", "hello"]
- conf = newconfig(["tests/hello"], inisource).envconfigs['py27']
+ conf = newconfig(["tests/hello"], inisource).envconfigs["py27"]
argv = conf.commands
assert argv[0] == ["cmd1", "tests/hello"]
tmpdir.ensure("tests", "hello")
- conf = newconfig(["tests/hello"], inisource).envconfigs['py27']
+ conf = newconfig(["tests/hello"], inisource).envconfigs["py27"]
argv = conf.commands
assert argv[0] == ["cmd1", "hello"]
@@ -1246,29 +1408,27 @@ class TestConfigTestEnv:
changedir = tests
commands = cmd1 {posargs}
"""
- conf = newconfig([], inisource).envconfigs['py27']
+ conf = newconfig([], inisource).envconfigs["py27"]
argv = conf.commands
assert argv[0] == ["cmd1"]
- conf = newconfig(["tests/hello"], inisource).envconfigs['py27']
+ conf = newconfig(["tests/hello"], inisource).envconfigs["py27"]
argv = conf.commands
assert argv[0] == ["cmd1", "tests/hello"]
tmpdir.ensure("tests", "hello")
- conf = newconfig(["tests/hello"], inisource).envconfigs['py27']
+ conf = newconfig(["tests/hello"], inisource).envconfigs["py27"]
argv = conf.commands
assert argv[0] == ["cmd1", "hello"]
- @pytest.mark.parametrize('envlist, deps', [
- (['py27'], ('pytest', 'pytest-cov')),
- (['py27', 'py34'], ('pytest', 'py{27,34}: pytest-cov'))
- ])
- def test_take_dependencies_from_other_testenv(
- self,
- newconfig,
- envlist,
- deps
- ):
+ @pytest.mark.parametrize(
+ "envlist, deps",
+ [
+ (["py27"], ("pytest", "pytest-cov")),
+ (["py27", "py34"], ("pytest", "py{27,34}: pytest-cov")),
+ ],
+ )
+ def test_take_dependencies_from_other_testenv(self, newconfig, envlist, deps):
inisource = """
[tox]
envlist = {envlist}
@@ -1280,15 +1440,14 @@ class TestConfigTestEnv:
fun
frob{{env:ENV_VAR:>1.0,<2.0}}
""".format(
- envlist=','.join(envlist),
- deps='\n' + '\n'.join([' ' * 17 + d for d in deps])
+ envlist=",".join(envlist), deps="\n" + "\n".join([" " * 17 + d for d in deps])
)
- conf = newconfig([], inisource).envconfigs['py27']
+ conf = newconfig([], inisource).envconfigs["py27"]
packages = [dep.name for dep in conf.deps]
- assert packages == ['pytest', 'pytest-cov', 'fun', 'frob>1.0,<2.0']
+ assert packages == ["pytest", "pytest-cov", "fun", "frob>1.0,<2.0"]
# https://github.com/tox-dev/tox/issues/706
- @pytest.mark.parametrize('envlist', [['py27', 'coverage', 'other']])
+ @pytest.mark.parametrize("envlist", [["py27", "coverage", "other"]])
def test_regression_test_issue_706(self, newconfig, envlist):
inisource = """
[tox]
@@ -1302,19 +1461,19 @@ class TestConfigTestEnv:
{{[testenv]deps}}
fun
""".format(
- envlist=','.join(envlist),
+ envlist=",".join(envlist)
)
- conf = newconfig([], inisource).envconfigs['coverage']
+ conf = newconfig([], inisource).envconfigs["coverage"]
packages = [dep.name for dep in conf.deps]
- assert packages == ['flake8', 'coverage']
+ assert packages == ["flake8", "coverage"]
- conf = newconfig([], inisource).envconfigs['other']
+ conf = newconfig([], inisource).envconfigs["other"]
packages = [dep.name for dep in conf.deps]
- assert packages == ['flake8']
+ assert packages == ["flake8"]
- conf = newconfig([], inisource).envconfigs['py27']
+ conf = newconfig([], inisource).envconfigs["py27"]
packages = [dep.name for dep in conf.deps]
- assert packages == ['flake8', 'fun']
+ assert packages == ["flake8", "fun"]
def test_take_dependencies_from_other_section(self, newconfig):
inisource = """
@@ -1332,9 +1491,9 @@ class TestConfigTestEnv:
fun
"""
conf = newconfig([], inisource)
- env = conf.envconfigs['python']
+ env = conf.envconfigs["python"]
packages = [dep.name for dep in env.deps]
- assert packages == ['pytest', 'pytest-cov', 'mock', 'fun']
+ assert packages == ["pytest", "pytest-cov", "mock", "fun"]
def test_multilevel_substitution(self, newconfig):
inisource = """
@@ -1357,9 +1516,9 @@ class TestConfigTestEnv:
fun
"""
conf = newconfig([], inisource)
- env = conf.envconfigs['python']
+ env = conf.envconfigs["python"]
packages = [dep.name for dep in env.deps]
- assert packages == ['pytest', 'pytest-cov', 'mock', 'fun']
+ assert packages == ["pytest", "pytest-cov", "mock", "fun"]
def test_recursive_substitution_cycle_fails(self, newconfig):
inisource = """
@@ -1384,8 +1543,8 @@ class TestConfigTestEnv:
[testenv]
changedir = {[common]changedir}
"""
- conf = newconfig([], inisource).envconfigs['python']
- assert conf.changedir.basename == 'testing'
+ conf = newconfig([], inisource).envconfigs["python"]
+ assert conf.changedir.basename == "testing"
assert conf.changedir.dirpath().realpath() == tmpdir.realpath()
def test_factors(self, newconfig):
@@ -1406,13 +1565,13 @@ class TestConfigTestEnv:
conf = newconfig([], inisource)
configs = conf.envconfigs
expected = ["dep-all", "dep-a", "dep-x", "dep-!b"]
- assert [dep.name for dep in configs['a-x'].deps] == expected
+ assert [dep.name for dep in configs["a-x"].deps] == expected
expected = ["dep-all", "dep-b", "dep-!a", "dep-!x"]
- assert [dep.name for dep in configs['b'].deps] == expected
+ assert [dep.name for dep in configs["b"].deps] == expected
expected = ["dep-all", "dep-a", "dep-x", "dep-!b"]
- assert [dep.name for dep in configs['a-x'].deps] == expected
+ assert [dep.name for dep in configs["a-x"].deps] == expected
expected = ["dep-all", "dep-b", "dep-!a", "dep-!x"]
- assert [dep.name for dep in configs['b'].deps] == expected
+ assert [dep.name for dep in configs["b"].deps] == expected
def test_factor_ops(self, newconfig):
inisource = """
@@ -1437,12 +1596,11 @@ class TestConfigTestEnv:
return [dep.name for dep in configs[env].deps]
assert get_deps("a-x") == ["dep-a-or-b", "dep-a-and-x", "dep-a-or-!x"]
- assert get_deps("a-y") == ["dep-a-or-b", "dep-ab-and-y",
- "dep-a-and-!x", "dep-a-or-!x",
- "dep-!a-or-!x"]
+ expected = ["dep-a-or-b", "dep-ab-and-y", "dep-a-and-!x", "dep-a-or-!x", "dep-!a-or-!x"]
+ assert get_deps("a-y") == expected
assert get_deps("b-x") == ["dep-a-or-b", "dep-!a-or-!x"]
- assert get_deps("b-y") == ["dep-a-or-b", "dep-ab-and-y", "dep-a-or-!x",
- "dep-!a-and-!x", "dep-!a-or-!x"]
+ expected = ["dep-a-or-b", "dep-ab-and-y", "dep-a-or-!x", "dep-!a-and-!x", "dep-!a-or-!x"]
+ assert get_deps("b-y") == expected
def test_envconfigs_based_on_factors(self, newconfig):
inisource = """
@@ -1486,7 +1644,7 @@ class TestConfigTestEnv:
conf = newconfig([], inisource)
configs = conf.envconfigs
for name, config in configs.items():
- assert config.basepython == 'python%s.%s' % (name[2], name[3])
+ assert config.basepython == "python{}.{}".format(name[2], name[3])
@pytest.mark.issue188
def test_factors_in_boolean(self, newconfig):
@@ -1526,7 +1684,7 @@ class TestConfigTestEnv:
deps = b: test
"""
configs = newconfig([], inisource).envconfigs
- assert set(configs.keys()) == {'py27-a', 'py27-b'}
+ assert set(configs.keys()) == {"py27-a", "py27-b"}
@pytest.mark.issue198
def test_factors_groups_touch(self, newconfig):
@@ -1539,7 +1697,7 @@ class TestConfigTestEnv:
a,b,x,y: dep
"""
configs = newconfig([], inisource).envconfigs
- assert set(configs.keys()) == {'a', 'a-x', 'b', 'b-x'}
+ assert set(configs.keys()) == {"a", "a-x", "b", "b-x"}
def test_period_in_factor(self, newconfig):
inisource = """
@@ -1565,6 +1723,7 @@ class TestConfigTestEnv:
class TestGlobalOptions:
+
def test_notest(self, newconfig):
config = newconfig([], "")
assert not config.option.notest
@@ -1579,24 +1738,21 @@ class TestGlobalOptions:
config = newconfig(["-vv"], "")
assert config.option.verbose_level == 2
- @pytest.mark.parametrize('args, expected', [
- ([], 0),
- (["-q"], 1),
- (["-qq"], 2),
- (["-qqq"], 3),
- ])
+ @pytest.mark.parametrize("args, expected", [([], 0), (["-q"], 1), (["-qq"], 2), (["-qqq"], 3)])
def test_quiet(self, args, expected, newconfig):
config = newconfig(args, "")
assert config.option.quiet_level == expected
def test_substitution_jenkins_default(self, monkeypatch, newconfig):
monkeypatch.setenv("HUDSON_URL", "xyz")
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:py27]
commands =
{distshare}
- """)
- conf = config.envconfigs['py27']
+ """
+ )
+ conf = config.envconfigs["py27"]
argv = conf.commands
expect_path = config.toxworkdir.join("distshare")
assert argv[0][0] == expect_path
@@ -1604,23 +1760,27 @@ class TestGlobalOptions:
def test_substitution_jenkins_context(self, tmpdir, monkeypatch, newconfig):
monkeypatch.setenv("HUDSON_URL", "xyz")
monkeypatch.setenv("WORKSPACE", tmpdir)
- config = newconfig("""
+ config = newconfig(
+ """
[tox:jenkins]
distshare = {env:WORKSPACE}/hello
[testenv:py27]
commands =
{distshare}
- """)
- conf = config.envconfigs['py27']
+ """
+ )
+ conf = config.envconfigs["py27"]
argv = conf.commands
assert argv[0][0] == config.distshare
assert config.distshare == tmpdir.join("hello")
def test_sdist_specification(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[tox]
sdistsrc = {distshare}/xyz.zip
- """)
+ """
+ )
assert config.sdistsrc == config.distshare.join("xyz.zip")
config = newconfig([], "")
assert not config.sdistsrc
@@ -1645,20 +1805,20 @@ class TestGlobalOptions:
assert config.envlist == ["py35", "py36"]
monkeypatch.setenv("TOXENV", "ALL")
config = newconfig([], inisource)
- assert config.envlist == ['py27', 'py35', 'py36']
+ assert config.envlist == ["py27", "py35", "py36"]
config = newconfig(["-eALL"], inisource)
- assert config.envlist == ['py27', 'py35', 'py36']
- config = newconfig(['-espam'], inisource)
+ assert config.envlist == ["py27", "py35", "py36"]
+ config = newconfig(["-espam"], inisource)
assert config.envlist == ["spam"]
def test_py_venv(self, newconfig):
config = newconfig(["-epy"], "")
- env = config.envconfigs['py']
+ env = config.envconfigs["py"]
assert str(env.basepython) == sys.executable
def test_correct_basepython_chosen_from_default_factors(self, newconfig):
envlist = list(tox.PYTHON.DEFAULT_FACTORS.keys())
- config = newconfig([], "[tox]\nenvlist=%s" % ", ".join(envlist))
+ config = newconfig([], "[tox]\nenvlist={}".format(", ".join(envlist)))
assert config.envlist == envlist
for name in config.envlist:
basepython = config.envconfigs[name].basepython
@@ -1667,9 +1827,9 @@ class TestGlobalOptions:
elif name.startswith("pypy"):
assert basepython == name
elif name in ("py2", "py3"):
- assert basepython == 'python' + name[-1]
- elif name == 'py':
- assert 'python' in basepython or "pypy" in basepython
+ assert basepython == "python" + name[-1]
+ elif name == "py":
+ assert "python" in basepython or "pypy" in basepython
else:
assert name.startswith("py")
assert basepython == "python{}.{}".format(name[2], name[3])
@@ -1727,7 +1887,7 @@ class TestGlobalOptions:
def test_defaultenv_commandline(self, newconfig):
config = newconfig(["-epy27"], "")
- env = config.envconfigs['py27']
+ env = config.envconfigs["py27"]
assert env.basepython == "python2.7"
assert not env.commands
@@ -1739,14 +1899,14 @@ class TestGlobalOptions:
commands= xyz
"""
config = newconfig([], inisource)
- env = config.envconfigs['py27']
+ env = config.envconfigs["py27"]
assert env.basepython == "python2.7"
- assert env.commands == [['xyz']]
+ assert env.commands == [["xyz"]]
class TestHashseedOption:
- def _get_envconfigs(self, newconfig, args=None, tox_ini=None,
- make_hashseed=None):
+
+ def _get_envconfigs(self, newconfig, args=None, tox_ini=None, make_hashseed=None):
if args is None:
args = []
if tox_ini is None:
@@ -1754,8 +1914,9 @@ class TestHashseedOption:
[testenv]
"""
if make_hashseed is None:
+
def make_hashseed():
- return '123456789'
+ return "123456789"
original_make_hashseed = tox.config.make_hashseed
tox.config.make_hashseed = make_hashseed
@@ -1766,37 +1927,36 @@ class TestHashseedOption:
return config.envconfigs
def _get_envconfig(self, newconfig, args=None, tox_ini=None):
- envconfigs = self._get_envconfigs(newconfig, args=args,
- tox_ini=tox_ini)
+ envconfigs = self._get_envconfigs(newconfig, args=args, tox_ini=tox_ini)
return envconfigs["python"]
def _check_hashseed(self, envconfig, expected):
- assert envconfig.setenv['PYTHONHASHSEED'] == expected
+ assert envconfig.setenv["PYTHONHASHSEED"] == expected
def _check_testenv(self, newconfig, expected, args=None, tox_ini=None):
envconfig = self._get_envconfig(newconfig, args=args, tox_ini=tox_ini)
self._check_hashseed(envconfig, expected)
def test_default(self, newconfig):
- self._check_testenv(newconfig, '123456789')
+ self._check_testenv(newconfig, "123456789")
def test_passing_integer(self, newconfig):
- args = ['--hashseed', '1']
- self._check_testenv(newconfig, '1', args=args)
+ args = ["--hashseed", "1"]
+ self._check_testenv(newconfig, "1", args=args)
def test_passing_string(self, newconfig):
- args = ['--hashseed', 'random']
- self._check_testenv(newconfig, 'random', args=args)
+ args = ["--hashseed", "random"]
+ self._check_testenv(newconfig, "random", args=args)
def test_passing_empty_string(self, newconfig):
- args = ['--hashseed', '']
- self._check_testenv(newconfig, '', args=args)
+ args = ["--hashseed", ""]
+ self._check_testenv(newconfig, "", args=args)
def test_passing_no_argument(self, newconfig):
"""Test that passing no arguments to --hashseed is not allowed."""
- args = ['--hashseed']
+ args = ["--hashseed"]
try:
- self._check_testenv(newconfig, '', args=args)
+ self._check_testenv(newconfig, "", args=args)
except SystemExit:
e = sys.exc_info()[1]
assert e.code == 2
@@ -1810,12 +1970,12 @@ class TestHashseedOption:
setenv =
PYTHONHASHSEED = 2
"""
- self._check_testenv(newconfig, '2', tox_ini=tox_ini)
- args = ['--hashseed', '1']
- self._check_testenv(newconfig, '2', args=args, tox_ini=tox_ini)
+ self._check_testenv(newconfig, "2", tox_ini=tox_ini)
+ args = ["--hashseed", "1"]
+ self._check_testenv(newconfig, "2", args=args, tox_ini=tox_ini)
def test_noset(self, newconfig):
- args = ['--hashseed', 'noset']
+ args = ["--hashseed", "noset"]
envconfig = self._get_envconfig(newconfig, args=args)
assert not envconfig.setenv.definitions
@@ -1825,8 +1985,8 @@ class TestHashseedOption:
setenv =
PYTHONHASHSEED = 2
"""
- args = ['--hashseed', 'noset']
- self._check_testenv(newconfig, '2', args=args, tox_ini=tox_ini)
+ args = ["--hashseed", "noset"]
+ self._check_testenv(newconfig, "2", args=args, tox_ini=tox_ini)
def test_one_random_hashseed(self, newconfig):
"""Check that different testenvs use the same random seed."""
@@ -1843,12 +2003,11 @@ class TestHashseedOption:
return str(next_seed[0])
# Check that make_hashseed() works.
- assert make_hashseed() == '1001'
- envconfigs = self._get_envconfigs(newconfig, tox_ini=tox_ini,
- make_hashseed=make_hashseed)
- self._check_hashseed(envconfigs["hash1"], '1002')
+ assert make_hashseed() == "1001"
+ envconfigs = self._get_envconfigs(newconfig, tox_ini=tox_ini, make_hashseed=make_hashseed)
+ self._check_hashseed(envconfigs["hash1"], "1002")
# Check that hash2's value is not '1003', for example.
- self._check_hashseed(envconfigs["hash2"], '1002')
+ self._check_hashseed(envconfigs["hash2"], "1002")
def test_setenv_in_one_testenv(self, newconfig):
"""Check using setenv in one of multiple testenvs."""
@@ -1859,19 +2018,22 @@ class TestHashseedOption:
[testenv:hash2]
"""
envconfigs = self._get_envconfigs(newconfig, tox_ini=tox_ini)
- self._check_hashseed(envconfigs["hash1"], '2')
- self._check_hashseed(envconfigs["hash2"], '123456789')
+ self._check_hashseed(envconfigs["hash1"], "2")
+ self._check_hashseed(envconfigs["hash2"], "123456789")
class TestSetenv:
+
def test_getdict_lazy(self, newconfig, monkeypatch):
monkeypatch.setenv("X", "2")
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:X]
key0 =
key1 = {env:X}
key2 = {env:Y:1}
- """)
+ """
+ )
envconfig = config.envconfigs["X"]
val = envconfig._reader.getdict_setenv("key0")
assert val["key1"] == "2"
@@ -1879,12 +2041,14 @@ class TestSetenv:
def test_getdict_lazy_update(self, newconfig, monkeypatch):
monkeypatch.setenv("X", "2")
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:X]
key0 =
key1 = {env:X}
key2 = {env:Y:1}
- """)
+ """
+ )
envconfig = config.envconfigs["X"]
val = envconfig._reader.getdict_setenv("key0")
d = {}
@@ -1893,97 +2057,114 @@ class TestSetenv:
def test_setenv_uses_os_environ(self, newconfig, monkeypatch):
monkeypatch.setenv("X", "1")
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:env1]
setenv =
X = {env:X}
- """)
+ """
+ )
assert config.envconfigs["env1"].setenv["X"] == "1"
def test_setenv_default_os_environ(self, newconfig, monkeypatch):
monkeypatch.delenv("X", raising=False)
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:env1]
setenv =
X = {env:X:2}
- """)
+ """
+ )
assert config.envconfigs["env1"].setenv["X"] == "2"
def test_setenv_uses_other_setenv(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:env1]
setenv =
Y = 5
X = {env:Y}
- """)
+ """
+ )
assert config.envconfigs["env1"].setenv["X"] == "5"
def test_setenv_recursive_direct(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv:env1]
setenv =
X = {env:X:3}
- """)
+ """
+ )
assert config.envconfigs["env1"].setenv["X"] == "3"
def test_setenv_overrides(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
setenv =
PYTHONPATH = something
ANOTHER_VAL=else
- """)
+ """
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['python']
- assert 'PYTHONPATH' in envconfig.setenv
- assert 'ANOTHER_VAL' in envconfig.setenv
- assert envconfig.setenv['PYTHONPATH'] == 'something'
- assert envconfig.setenv['ANOTHER_VAL'] == 'else'
+ envconfig = config.envconfigs["python"]
+ assert "PYTHONPATH" in envconfig.setenv
+ assert "ANOTHER_VAL" in envconfig.setenv
+ assert envconfig.setenv["PYTHONPATH"] == "something"
+ assert envconfig.setenv["ANOTHER_VAL"] == "else"
def test_setenv_with_envdir_and_basepython(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
setenv =
VAL = {envdir}
basepython = {env:VAL}
- """)
+ """
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['python']
- assert 'VAL' in envconfig.setenv
- assert envconfig.setenv['VAL'] == envconfig.envdir
+ envconfig = config.envconfigs["python"]
+ assert "VAL" in envconfig.setenv
+ assert envconfig.setenv["VAL"] == envconfig.envdir
assert envconfig.basepython == envconfig.envdir
def test_setenv_ordering_1(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[testenv]
setenv=
VAL={envdir}
commands=echo {env:VAL}
- """)
+ """
+ )
assert len(config.envconfigs) == 1
- envconfig = config.envconfigs['python']
- assert 'VAL' in envconfig.setenv
- assert envconfig.setenv['VAL'] == envconfig.envdir
+ envconfig = config.envconfigs["python"]
+ assert "VAL" in envconfig.setenv
+ assert envconfig.setenv["VAL"] == envconfig.envdir
assert str(envconfig.envdir) in envconfig.commands[0]
def test_setenv_cross_section_subst_issue294(self, monkeypatch, newconfig):
"""test that we can do cross-section substitution with setenv"""
- monkeypatch.delenv('TEST', raising=False)
- config = newconfig("""
+ monkeypatch.delenv("TEST", raising=False)
+ config = newconfig(
+ """
[section]
x =
NOT_TEST={env:TEST:defaultvalue}
[testenv]
setenv = {[section]x}
- """)
+ """
+ )
envconfig = config.envconfigs["python"]
assert envconfig.setenv["NOT_TEST"] == "defaultvalue"
def test_setenv_cross_section_subst_twice(self, monkeypatch, newconfig):
"""test that we can do cross-section substitution with setenv"""
- monkeypatch.delenv('TEST', raising=False)
- config = newconfig("""
+ monkeypatch.delenv("TEST", raising=False)
+ config = newconfig(
+ """
[section]
x = NOT_TEST={env:TEST:defaultvalue}
[section1]
@@ -1991,37 +2172,43 @@ class TestSetenv:
[testenv]
setenv = {[section1]y}
- """)
+ """
+ )
envconfig = config.envconfigs["python"]
assert envconfig.setenv["NOT_TEST"] == "defaultvalue"
def test_setenv_cross_section_mixed(self, monkeypatch, newconfig):
"""test that we can do cross-section substitution with setenv"""
- monkeypatch.delenv('TEST', raising=False)
- config = newconfig("""
+ monkeypatch.delenv("TEST", raising=False)
+ config = newconfig(
+ """
[section]
x = NOT_TEST={env:TEST:defaultvalue}
[testenv]
setenv = {[section]x}
y = 7
- """)
+ """
+ )
envconfig = config.envconfigs["python"]
assert envconfig.setenv["NOT_TEST"] == "defaultvalue"
assert envconfig.setenv["y"] == "7"
class TestIndexServer:
+
def test_indexserver(self, newconfig):
- config = newconfig("""
+ config = newconfig(
+ """
[tox]
indexserver =
name1 = XYZ
name2 = ABC
- """)
- assert config.indexserver['default'].url is None
- assert config.indexserver['name1'].url == "XYZ"
- assert config.indexserver['name2'].url == "ABC"
+ """
+ )
+ assert config.indexserver["default"].url is None
+ assert config.indexserver["name1"].url == "XYZ"
+ assert config.indexserver["name2"].url == "ABC"
def test_parse_indexserver(self, newconfig):
inisource = """
@@ -2031,14 +2218,14 @@ class TestIndexServer:
name1 = whatever
"""
config = newconfig([], inisource)
- assert config.indexserver['default'].url == "http://pypi.somewhere.org"
- assert config.indexserver['name1'].url == "whatever"
- config = newconfig(['-i', 'qwe'], inisource)
- assert config.indexserver['default'].url == "qwe"
- assert config.indexserver['name1'].url == "whatever"
- config = newconfig(['-i', 'name1=abc', '-i', 'qwe2'], inisource)
- assert config.indexserver['default'].url == "qwe2"
- assert config.indexserver['name1'].url == "abc"
+ assert config.indexserver["default"].url == "http://pypi.somewhere.org"
+ assert config.indexserver["name1"].url == "whatever"
+ config = newconfig(["-i", "qwe"], inisource)
+ assert config.indexserver["default"].url == "qwe"
+ assert config.indexserver["name1"].url == "whatever"
+ config = newconfig(["-i", "name1=abc", "-i", "qwe2"], inisource)
+ assert config.indexserver["default"].url == "qwe2"
+ assert config.indexserver["name1"].url == "abc"
config = newconfig(["-i", "ALL=xzy"], inisource)
assert len(config.indexserver) == 2
@@ -2055,20 +2242,23 @@ class TestIndexServer:
pypi = http://pypi.org/simple
"""
config = newconfig([], inisource)
- expected = "file://%s/.pip/downloads/simple" % config.homedir
- assert config.indexserver['default'].url == expected
- assert config.indexserver['local1'].url == config.indexserver['default'].url
+ expected = "file://{}/.pip/downloads/simple".format(config.homedir)
+ assert config.indexserver["default"].url == expected
+ assert config.indexserver["local1"].url == config.indexserver["default"].url
class TestConfigConstSubstitutions:
- @pytest.mark.parametrize('pathsep', [':', ';'])
+
+ @pytest.mark.parametrize("pathsep", [":", ";"])
def test_replace_pathsep_unix(self, monkeypatch, newconfig, pathsep):
- monkeypatch.setattr('os.pathsep', pathsep)
- config = newconfig("""
+ monkeypatch.setattr("os.pathsep", pathsep)
+ config = newconfig(
+ """
[testenv]
setenv =
PATH = dira{:}dirb{:}dirc
- """)
+ """
+ )
envconfig = config.envconfigs["python"]
assert envconfig.setenv["PATH"] == pathsep.join(["dira", "dirb", "dirc"])
@@ -2077,34 +2267,36 @@ class TestConfigConstSubstitutions:
regex = tox.config.Replacer.RE_ITEM_REF
match = next(regex.finditer("{:}"))
mdict = match.groupdict()
- assert mdict['sub_type'] is None
- assert mdict['substitution_value'] == ""
- assert mdict['default_value'] == ""
+ assert mdict["sub_type"] is None
+ assert mdict["substitution_value"] == ""
+ assert mdict["default_value"] == ""
class TestParseEnv:
+
def test_parse_recreate(self, newconfig):
inisource = ""
config = newconfig([], inisource)
- assert not config.envconfigs['python'].recreate
- config = newconfig(['--recreate'], inisource)
- assert config.envconfigs['python'].recreate
- config = newconfig(['-r'], inisource)
- assert config.envconfigs['python'].recreate
+ assert not config.envconfigs["python"].recreate
+ config = newconfig(["--recreate"], inisource)
+ assert config.envconfigs["python"].recreate
+ config = newconfig(["-r"], inisource)
+ assert config.envconfigs["python"].recreate
inisource = """
[testenv:hello]
recreate = True
"""
config = newconfig([], inisource)
- assert config.envconfigs['hello'].recreate
+ assert config.envconfigs["hello"].recreate
class TestCmdInvocation:
+
def test_help(self, cmd):
result = cmd("-h")
assert not result.ret
assert not result.err
- assert re.match(r'usage:.*help.*', result.out, re.DOTALL)
+ assert re.match(r"usage:.*help.*", result.out, re.DOTALL)
def test_version_simple(self, cmd):
result = cmd("--version")
@@ -2112,25 +2304,26 @@ class TestCmdInvocation:
assert "{} imported from".format(tox.__version__) in result.out
def test_version_no_plugins(self):
- pm = PluginManager('fakeprject')
+ pm = PluginManager("fakeprject")
version_info = get_version_info(pm)
assert "imported from" in version_info
assert "registered plugins:" not in version_info
def test_version_with_normal_plugin(self, monkeypatch):
+
def fake_normal_plugin_distinfo():
+
class MockModule:
- __file__ = 'some-file'
+ __file__ = "some-file"
class MockEggInfo:
- project_name = 'some-project'
- version = '1.0'
+ project_name = "some-project"
+ version = "1.0"
return [(MockModule, MockEggInfo)]
- pm = PluginManager('fakeproject')
- monkeypatch.setattr(
- pm, 'list_plugin_distinfo', fake_normal_plugin_distinfo)
+ pm = PluginManager("fakeproject")
+ monkeypatch.setattr(pm, "list_plugin_distinfo", fake_normal_plugin_distinfo)
version_info = get_version_info(pm)
assert "registered plugins:" in version_info
assert "some-file" in version_info
@@ -2138,20 +2331,22 @@ class TestCmdInvocation:
assert "1.0" in version_info
def test_version_with_fileless_module(self, monkeypatch):
+
def fake_no_file_plugin_distinfo():
+
class MockModule:
+
def __repr__(self):
return "some-repr"
class MockEggInfo:
- project_name = 'some-project'
- version = '1.0'
+ project_name = "some-project"
+ version = "1.0"
return [(MockModule(), MockEggInfo)]
- pm = PluginManager('fakeproject')
- monkeypatch.setattr(
- pm, 'list_plugin_distinfo', fake_no_file_plugin_distinfo)
+ pm = PluginManager("fakeproject")
+ monkeypatch.setattr(pm, "list_plugin_distinfo", fake_no_file_plugin_distinfo)
version_info = get_version_info(pm)
assert "registered plugins:" in version_info
assert "some-project" in version_info
@@ -2159,8 +2354,10 @@ class TestCmdInvocation:
assert "1.0" in version_info
def test_listenvs(self, cmd, initproj):
- initproj('listenvs', filedefs={
- 'tox.ini': '''
+ initproj(
+ "listenvs",
+ filedefs={
+ "tox.ini": """
[tox]
envlist=py36,py27,py34,pypy,docs
description= py27: run pytest on Python 2.7
@@ -2174,14 +2371,17 @@ class TestCmdInvocation:
[testenv:docs]
changedir = docs
- '''
- })
+ """
+ },
+ )
result = cmd("-l")
- assert result.outlines == ['py36', 'py27', 'py34', 'pypy', 'docs']
+ assert result.outlines == ["py36", "py27", "py34", "pypy", "docs"]
def test_listenvs_verbose_description(self, cmd, initproj):
- initproj('listenvs_verbose_description', filedefs={
- 'tox.ini': '''
+ initproj(
+ "listenvs_verbose_description",
+ filedefs={
+ "tox.ini": """
[tox]
envlist=py36,py27,py34,pypy,docs
[testenv]
@@ -2198,20 +2398,25 @@ class TestCmdInvocation:
[testenv:docs]
changedir = docs
description = let me overwrite that
- '''
- })
+ """
+ },
+ )
result = cmd("-lv")
- assert result.outlines[2:] == [
- 'default environments:',
- 'py36 -> run pytest on Python 3.6',
- 'py27 -> run pytest on Python 2.7',
- 'py34 -> run pytest on Python 3.4',
- 'pypy -> publish to pypy',
- 'docs -> let me overwrite that']
+ expected = [
+ "default environments:",
+ "py36 -> run pytest on Python 3.6",
+ "py27 -> run pytest on Python 2.7",
+ "py34 -> run pytest on Python 3.4",
+ "pypy -> publish to pypy",
+ "docs -> let me overwrite that",
+ ]
+ assert result.outlines[2:] == expected
def test_listenvs_all(self, cmd, initproj):
- initproj('listenvs_all', filedefs={
- 'tox.ini': '''
+ initproj(
+ "listenvs_all",
+ filedefs={
+ "tox.ini": """
[tox]
envlist=py36,py27,py34,pypy,docs
@@ -2220,14 +2425,18 @@ class TestCmdInvocation:
[testenv:docs]
changedir = docs
- '''
- })
+ """
+ },
+ )
result = cmd("-a")
- assert result.outlines == ['py36', 'py27', 'py34', 'pypy', 'docs', 'notincluded']
+ expected = ["py36", "py27", "py34", "pypy", "docs", "notincluded"]
+ assert result.outlines == expected
def test_listenvs_all_verbose_description(self, cmd, initproj):
- initproj('listenvs_all_verbose_description', filedefs={
- 'tox.ini': '''
+ initproj(
+ "listenvs_all_verbose_description",
+ filedefs={
+ "tox.ini": """
[tox]
envlist={py27,py36}-{windows,linux} # py35
[testenv]
@@ -2240,8 +2449,9 @@ class TestCmdInvocation:
[testenv:docs]
changedir = docs
- ''',
- })
+ """
+ },
+ )
result = cmd("-av")
expected = [
"default environments:",
@@ -2251,45 +2461,54 @@ class TestCmdInvocation:
"py36-linux -> run pytest on Python 3.6 on Linux platform",
"",
"additional environments:",
- "docs -> generate documentation"]
+ "docs -> generate documentation",
+ ]
assert result.outlines[-len(expected):] == expected
def test_listenvs_all_verbose_description_no_additional_environments(self, cmd, initproj):
- initproj('listenvs_all_verbose_description', filedefs={
- 'tox.ini': '''
+ initproj(
+ "listenvs_all_verbose_description",
+ filedefs={
+ "tox.ini": """
[tox]
envlist=py27,py36
- '''
- })
+ """
+ },
+ )
result = cmd("-av")
- expected = ["default environments:",
- "py27 -> [no description]",
- "py36 -> [no description]"]
+ expected = [
+ "default environments:", "py27 -> [no description]", "py36 -> [no description]"
+ ]
assert result.out.splitlines()[-3:] == expected
- assert 'additional environments' not in result.out
+ assert "additional environments" not in result.out
def test_config_specific_ini(self, tmpdir, cmd):
ini = tmpdir.ensure("hello.ini")
result = cmd("-c", ini, "--showconfig")
assert not result.ret
- assert result.outlines[1] == 'config-file: {}'.format(ini)
+ assert result.outlines[1] == "config-file: {}".format(ini)
def test_no_tox_ini(self, cmd, initproj):
- initproj("noini-0.5", )
+ initproj("noini-0.5")
result = cmd()
assert result.ret
- assert result.out == ''
+ assert result.out == ""
assert result.err == "ERROR: toxini file 'tox.ini' not found\n"
def test_override_workdir(self, cmd, initproj):
baddir = "badworkdir-123"
gooddir = "overridden-234"
- initproj("overrideworkdir-0.5", filedefs={
- 'tox.ini': '''
+ initproj(
+ "overrideworkdir-0.5",
+ filedefs={
+ "tox.ini": """
[tox]
- toxworkdir=%s
- ''' % baddir,
- })
+ toxworkdir={}
+ """.format(
+ baddir
+ )
+ },
+ )
result = cmd("--workdir", gooddir, "--showconfig")
assert not result.ret
assert gooddir in result.out
@@ -2298,46 +2517,54 @@ class TestCmdInvocation:
assert not py.path.local(baddir).check()
def test_showconfig_with_force_dep_version(self, cmd, initproj):
- initproj('force_dep_version', filedefs={
- 'tox.ini': '''
+ initproj(
+ "force_dep_version",
+ filedefs={
+ "tox.ini": """
[tox]
[testenv]
deps=
dep1==2.3
dep2
- ''',
- })
+ """
+ },
+ )
result = cmd("--showconfig")
assert result.ret == 0
- assert any(re.match(r'.*deps.*dep1==2.3, dep2.*', l) for l in result.outlines)
+ assert any(re.match(r".*deps.*dep1==2.3, dep2.*", l) for l in result.outlines)
# override dep1 specific version, and force version for dep2
- result = cmd("--showconfig", "--force-dep=dep1",
- "--force-dep=dep2==5.0")
+ result = cmd("--showconfig", "--force-dep=dep1", "--force-dep=dep2==5.0")
assert result.ret == 0
- assert any(re.match(r'.*deps.*dep1, dep2==5.0.*', l) for l in result.outlines)
+ assert any(re.match(r".*deps.*dep1, dep2==5.0.*", l) for l in result.outlines)
- @pytest.mark.xfail("'pypy' not in sys.executable", reason='Upstream bug. See #203')
+ @pytest.mark.xfail("'pypy' not in sys.executable", reason="Upstream bug. See #203")
def test_colon_symbol_in_directory_name(self, cmd, initproj):
- initproj('colon:_symbol_in_dir_name', filedefs={
- 'tox.ini': '''
+ initproj(
+ "colon:_symbol_in_dir_name",
+ filedefs={
+ "tox.ini": """
[tox]
envlist = py27
[testenv]
commands = pip --version
- '''
- })
+ """
+ },
+ )
result = cmd()
assert result.ret == 0
-@pytest.mark.parametrize("cmdline,envlist", [
- ("-e py36", ['py36']),
- ("-e py36,py34", ['py36', 'py34']),
- ("-e py36,py36", ['py36', 'py36']),
- ("-e py36,py34 -e py34,py27", ['py36', 'py34', 'py34', 'py27'])
-])
+@pytest.mark.parametrize(
+ "cmdline,envlist",
+ [
+ ("-e py36", ["py36"]),
+ ("-e py36,py34", ["py36", "py34"]),
+ ("-e py36,py36", ["py36", "py36"]),
+ ("-e py36,py34 -e py34,py27", ["py36", "py34", "py34", "py27"]),
+ ],
+)
def test_env_spec(cmdline, envlist):
args = cmdline.split()
config = parseconfig(args)
@@ -2345,33 +2572,64 @@ def test_env_spec(cmdline, envlist):
class TestCommandParser:
+
def test_command_parser_for_word(self):
- p = CommandParser('word')
- assert list(p.words()) == ['word']
+ p = CommandParser("word")
+ assert list(p.words()) == ["word"]
def test_command_parser_for_posargs(self):
- p = CommandParser('[]')
- assert list(p.words()) == ['[]']
+ p = CommandParser("[]")
+ assert list(p.words()) == ["[]"]
def test_command_parser_for_multiple_words(self):
- p = CommandParser('w1 w2 w3 ')
- assert list(p.words()) == ['w1', ' ', 'w2', ' ', 'w3']
+ p = CommandParser("w1 w2 w3 ")
+ assert list(p.words()) == ["w1", " ", "w2", " ", "w3"]
def test_command_parser_for_substitution_with_spaces(self):
- p = CommandParser('{sub:something with spaces}')
- assert list(p.words()) == ['{sub:something with spaces}']
+ p = CommandParser("{sub:something with spaces}")
+ assert list(p.words()) == ["{sub:something with spaces}"]
def test_command_parser_with_complex_word_set(self):
complex_case = (
- 'word [] [literal] {something} {some:other thing} w{ord} w{or}d w{ord} '
- 'w{o:rd} w{o:r}d {w:or}d w[]ord {posargs:{a key}}')
+ "word [] [literal] {something} {some:other thing} w{ord} w{or}d w{ord} "
+ "w{o:rd} w{o:r}d {w:or}d w[]ord {posargs:{a key}}"
+ )
p = CommandParser(complex_case)
parsed = list(p.words())
expected = [
- 'word', ' ', '[]', ' ', '[literal]', ' ', '{something}', ' ', '{some:other thing}',
- ' ', 'w', '{ord}', ' ', 'w', '{or}', 'd', ' ', 'w', '{ord}', ' ', 'w', '{o:rd}', ' ',
- 'w', '{o:r}', 'd', ' ', '{w:or}', 'd',
- ' ', 'w[]ord', ' ', '{posargs:{a key}}'
+ "word",
+ " ",
+ "[]",
+ " ",
+ "[literal]",
+ " ",
+ "{something}",
+ " ",
+ "{some:other thing}",
+ " ",
+ "w",
+ "{ord}",
+ " ",
+ "w",
+ "{or}",
+ "d",
+ " ",
+ "w",
+ "{ord}",
+ " ",
+ "w",
+ "{o:rd}",
+ " ",
+ "w",
+ "{o:r}",
+ "d",
+ " ",
+ "{w:or}",
+ "d",
+ " ",
+ "w[]ord",
+ " ",
+ "{posargs:{a key}}",
]
assert parsed == expected
@@ -2380,29 +2638,35 @@ class TestCommandParser:
cmd = "cmd1 {item1}\n {item2}"
p = CommandParser(cmd)
parsed = list(p.words())
- assert parsed == ['cmd1', ' ', '{item1}', '\n ', '{item2}']
+ assert parsed == ["cmd1", " ", "{item1}", "\n ", "{item2}"]
def test_command_with_split_line_in_subst_arguments(self):
- cmd = dedent(""" cmd2 {posargs:{item2}
- other}""")
+ cmd = dedent(
+ """ cmd2 {posargs:{item2}
+ other}"""
+ )
p = CommandParser(cmd)
parsed = list(p.words())
- assert parsed == ['cmd2', ' ', '{posargs:{item2}\n other}']
+ expected = ["cmd2", " ", "{posargs:{item2}\n other}"]
+ assert parsed == expected
def test_command_parsing_for_issue_10(self):
cmd = "nosetests -v -a !deferred --with-doctest []"
p = CommandParser(cmd)
parsed = list(p.words())
- assert parsed == [
- 'nosetests', ' ', '-v', ' ', '-a', ' ', '!deferred', ' ',
- '--with-doctest', ' ', '[]'
+ expected = [
+ "nosetests", " ", "-v", " ", "-a", " ", "!deferred", " ", "--with-doctest", " ", "[]"
]
+ assert parsed == expected
# @mark_dont_run_on_windows
def test_commands_with_backslash(self, newconfig):
- config = newconfig([r"hello\world"], """
+ config = newconfig(
+ [r"hello\world"],
+ """
[testenv:py36]
commands = some {posargs}
- """)
+ """,
+ )
envconfig = config.envconfigs["py36"]
assert envconfig.commands[0] == ["some", r"hello\world"]
diff --git a/tests/test_interpreters.py b/tests/test_interpreters.py
index 83dfab5f..cba8e639 100644
--- a/tests/test_interpreters.py
+++ b/tests/test_interpreters.py
@@ -9,9 +9,9 @@ import pytest
import tox
from tox._pytestplugin import mark_dont_run_on_posix
from tox.config import get_plugin_manager
-from tox.interpreters import (
- ExecFailed, InterpreterInfo, Interpreters, NoInterpreterInfo, pyinfo,
- run_and_get_interpreter_info, sitepackagesdir, tox_get_python_executable)
+from tox.interpreters import ExecFailed, InterpreterInfo, Interpreters, NoInterpreterInfo
+from tox.interpreters import pyinfo, run_and_get_interpreter_info, sitepackagesdir
+from tox.interpreters import tox_get_python_executable
@pytest.fixture(name="interpreters")
@@ -25,11 +25,11 @@ def test_locate_via_py(monkeypatch):
from tox.interpreters import locate_via_py
def fake_find_exe(exe):
- assert exe == 'py'
- return 'py'
+ assert exe == "py"
+ return "py"
def fake_popen(cmd, stdout, stderr):
- assert cmd[:3] == ('py', '-3.2', '-c')
+ assert cmd[:3] == ("py", "-3.2", "-c")
# need to pipe all stdout to collect the version information & need to
# do the same for stderr output to avoid it being forwarded as the
@@ -47,12 +47,13 @@ def test_locate_via_py(monkeypatch):
return proc
- monkeypatch.setattr(distutils.spawn, 'find_executable', fake_find_exe)
- monkeypatch.setattr(subprocess, 'Popen', fake_popen)
- assert locate_via_py('3', '2') == sys.executable
+ monkeypatch.setattr(distutils.spawn, "find_executable", fake_find_exe)
+ monkeypatch.setattr(subprocess, "Popen", fake_popen)
+ assert locate_via_py("3", "2") == sys.executable
def test_tox_get_python_executable():
+
class envconfig:
basepython = sys.executable
envname = "pyxx"
@@ -60,10 +61,10 @@ def test_tox_get_python_executable():
p = tox_get_python_executable(envconfig)
assert p == py.path.local(sys.executable)
for major, minor in tox.PYTHON.CPYTHON_VERSION_TUPLES:
- name = "python%s.%s" % (major, minor)
+ name = "python{}.{}".format(major, minor)
if tox.INFO.IS_WIN:
- pydir = "python%s%s" % (major, minor)
- x = py.path.local(r"c:\%s" % pydir)
+ pydir = "python{}{}".format(major, minor)
+ x = py.path.local(r"c:\{}".format(pydir))
print(x)
if not x.check():
continue
@@ -73,15 +74,15 @@ def test_tox_get_python_executable():
envconfig.basepython = name
p = tox_get_python_executable(envconfig)
assert p
- popen = subprocess.Popen([str(p), '-V'], stderr=subprocess.PIPE,
- stdout=subprocess.PIPE)
+ popen = subprocess.Popen([str(p), "-V"], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
stdout, stderr = popen.communicate()
assert not stdout or not stderr
- all_output = stderr.decode('ascii') + stdout.decode('ascii')
- assert "%s.%s" % (major, minor) in all_output
+ all_output = stderr.decode("ascii") + stdout.decode("ascii")
+ assert "{}.{}".format(major, minor) in all_output
def test_find_executable_extra(monkeypatch):
+
@staticmethod
def sysfind(_):
return "hello"
@@ -105,7 +106,9 @@ def test_run_and_get_interpreter_info():
class TestInterpreters:
+
def test_get_executable(self, interpreters):
+
class envconfig:
basepython = sys.executable
envname = "pyxx"
@@ -118,6 +121,7 @@ class TestInterpreters:
assert info.runnable
def test_get_executable_no_exist(self, interpreters):
+
class envconfig:
basepython = "1lkj23"
envname = "pyxx"
@@ -130,6 +134,7 @@ class TestInterpreters:
assert not info.runnable
def test_get_sitepackagesdir_error(self, interpreters):
+
class envconfig:
basepython = sys.executable
envname = "123"
@@ -150,6 +155,7 @@ def test_pyinfo(monkeypatch):
def test_sitepackagesdir(monkeypatch):
import distutils.sysconfig as sysconfig
+
test_envdir = "holy grail"
test_dir = "Now go away or I will taunt you a second time."
@@ -171,9 +177,14 @@ def test_exec_failed():
class TestInterpreterInfo:
+
@staticmethod
- def info(name="my-name", executable="my-executable",
- version_info="my-version-info", sysplatform="my-sys-platform"):
+ def info(
+ name="my-name",
+ executable="my-executable",
+ version_info="my-version-info",
+ sysplatform="my-sys-platform",
+ ):
return InterpreterInfo(name, executable, version_info, sysplatform)
def test_runnable(self):
@@ -197,6 +208,7 @@ class TestInterpreterInfo:
class TestNoInterpreterInfo:
+
def test_runnable(self):
assert not NoInterpreterInfo("foo").runnable
assert not NoInterpreterInfo("foo", executable=sys.executable).runnable
@@ -210,8 +222,7 @@ class TestNoInterpreterInfo:
assert x.err == "not found"
def test_set_data(self):
- x = NoInterpreterInfo(
- "migraine", executable="my-executable", out="my-out", err="my-err")
+ x = NoInterpreterInfo("migraine", executable="my-executable", out="my-out", err="my-err")
assert x.name == "migraine"
assert x.executable == "my-executable"
assert x.version_info is None
diff --git a/tests/test_pytest_plugins.py b/tests/test_pytest_plugins.py
index 126aa2d0..326ba48b 100644
--- a/tests/test_pytest_plugins.py
+++ b/tests/test_pytest_plugins.py
@@ -10,89 +10,97 @@ from tox._pytestplugin import _filedefs_contains, _path_parts
class TestInitProj:
- @pytest.mark.parametrize('kwargs', (
- {},
- {'src_root': None},
- {'src_root': ''},
- {'src_root': '.'}))
+
+ @pytest.mark.parametrize(
+ "kwargs", ({}, {"src_root": None}, {"src_root": ""}, {"src_root": "."})
+ )
def test_no_src_root(self, kwargs, tmpdir, initproj):
- initproj('black_knight-42', **kwargs)
- init_file = tmpdir.join('black_knight', 'black_knight', '__init__.py')
+ initproj("black_knight-42", **kwargs)
+ init_file = tmpdir.join("black_knight", "black_knight", "__init__.py")
assert init_file.read_binary() == b"__version__ = '42'"
def test_existing_src_root(self, tmpdir, initproj):
- initproj('spam-666', src_root='ham')
- assert not tmpdir.join('spam', 'spam').check(exists=1)
- init_file = tmpdir.join('spam', 'ham', 'spam', '__init__.py')
+ initproj("spam-666", src_root="ham")
+ assert not tmpdir.join("spam", "spam").check(exists=1)
+ init_file = tmpdir.join("spam", "ham", "spam", "__init__.py")
assert init_file.read_binary() == b"__version__ = '666'"
def test_prebuilt_src_dir_with_no_src_root(self, tmpdir, initproj):
- initproj('spam-1.0', filedefs={'spam': {}})
- src_dir = tmpdir.join('spam', 'spam')
+ initproj("spam-1.0", filedefs={"spam": {}})
+ src_dir = tmpdir.join("spam", "spam")
assert src_dir.check(dir=1)
- assert not src_dir.join('__init__.py').check(exists=1)
+ assert not src_dir.join("__init__.py").check(exists=1)
def test_prebuilt_src_dir_with_src_root(self, tmpdir, initproj):
initproj(
- 'spam-1.0',
- filedefs={'incontinentia': {'spam': {'__init__.py': 'buttocks'}}},
- src_root='incontinentia')
- assert not tmpdir.join('spam', 'spam').check(exists=1)
- init_file = tmpdir.join('spam', 'incontinentia', 'spam', '__init__.py')
- assert init_file.read_binary() == b'buttocks'
-
- def test_broken_py_path_local_join_workaround_on_Windows(
- self, tmpdir, initproj, monkeypatch):
+ "spam-1.0",
+ filedefs={"incontinentia": {"spam": {"__init__.py": "buttocks"}}},
+ src_root="incontinentia",
+ )
+ assert not tmpdir.join("spam", "spam").check(exists=1)
+ init_file = tmpdir.join("spam", "incontinentia", "spam", "__init__.py")
+ assert init_file.read_binary() == b"buttocks"
+
+ def test_broken_py_path_local_join_workaround_on_Windows(self, tmpdir, initproj, monkeypatch):
# construct an absolute folder path for our src_root folder without the
# Windows drive indicator
- src_root = tmpdir.join('spam')
+ src_root = tmpdir.join("spam")
src_root = _path_parts(src_root)
- src_root[0] = ''
- src_root = '/'.join(src_root)
+ src_root[0] = ""
+ src_root = "/".join(src_root)
# make sure tmpdir drive is the current one so the constructed src_root
# folder path gets interpreted correctly on Windows
monkeypatch.chdir(tmpdir)
# will throw an assertion error if the bug is not worked around
- initproj('spam-666', src_root=src_root)
+ initproj("spam-666", src_root=src_root)
- init_file = tmpdir.join('spam', 'spam', '__init__.py')
+ init_file = tmpdir.join("spam", "spam", "__init__.py")
assert init_file.read_binary() == b"__version__ = '666'"
class TestPathParts:
- @pytest.mark.parametrize('input, expected', (
- ('', []),
- ('/', ['/']),
- ('//', ['//']),
- ('/a', ['/', 'a']),
- ('/a/', ['/', 'a']),
- ('/a/b', ['/', 'a', 'b']),
- ('a', ['a']),
- ('a/b', ['a', 'b'])))
+
+ @pytest.mark.parametrize(
+ "input, expected",
+ (
+ ("", []),
+ ("/", ["/"]),
+ ("//", ["//"]),
+ ("/a", ["/", "a"]),
+ ("/a/", ["/", "a"]),
+ ("/a/b", ["/", "a", "b"]),
+ ("a", ["a"]),
+ ("a/b", ["a", "b"]),
+ ),
+ )
def test_path_parts(self, input, expected):
assert _path_parts(input) == expected
def test_on_py_path(self):
cwd_parts = _path_parts(py.path.local())
- folder_parts = _path_parts(py.path.local('a/b/c'))
- assert folder_parts[len(cwd_parts):] == ['a', 'b', 'c']
-
-
-@pytest.mark.parametrize('base, filedefs, target, expected', (
- ('/base', {}, '', False),
- ('/base', {}, '/base', False),
- ('/base', {'a': {'b': 'data'}}, '', True),
- ('/base', {'a': {'b': 'data'}}, 'a', True),
- ('/base', {'a': {'b': 'data'}}, 'a/b', True),
- ('/base', {'a': {'b': 'data'}}, 'a/x', False),
- ('/base', {'a': {'b': 'data'}}, 'a/b/c', False),
- ('/base', {'a': {'b': 'data'}}, '/base', True),
- ('/base', {'a': {'b': 'data'}}, '/base/a', True),
- ('/base', {'a': {'b': 'data'}}, '/base/a/b', True),
- ('/base', {'a': {'b': 'data'}}, '/base/a/x', False),
- ('/base', {'a': {'b': 'data'}}, '/base/a/b/c', False),
- ('/base', {'a': {'b': 'data'}}, '/a', False)))
+ folder_parts = _path_parts(py.path.local("a/b/c"))
+ assert folder_parts[len(cwd_parts):] == ["a", "b", "c"]
+
+
+@pytest.mark.parametrize(
+ "base, filedefs, target, expected",
+ (
+ ("/base", {}, "", False),
+ ("/base", {}, "/base", False),
+ ("/base", {"a": {"b": "data"}}, "", True),
+ ("/base", {"a": {"b": "data"}}, "a", True),
+ ("/base", {"a": {"b": "data"}}, "a/b", True),
+ ("/base", {"a": {"b": "data"}}, "a/x", False),
+ ("/base", {"a": {"b": "data"}}, "a/b/c", False),
+ ("/base", {"a": {"b": "data"}}, "/base", True),
+ ("/base", {"a": {"b": "data"}}, "/base/a", True),
+ ("/base", {"a": {"b": "data"}}, "/base/a/b", True),
+ ("/base", {"a": {"b": "data"}}, "/base/a/x", False),
+ ("/base", {"a": {"b": "data"}}, "/base/a/b/c", False),
+ ("/base", {"a": {"b": "data"}}, "/a", False),
+ ),
+)
def test_filedefs_contains(base, filedefs, target, expected):
assert bool(_filedefs_contains(base, filedefs, target)) == expected
diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py
index 666ae18f..0c9ffff0 100644
--- a/tests/test_quickstart.py
+++ b/tests/test_quickstart.py
@@ -3,14 +3,14 @@ import os
import pytest
import tox
-from tox._quickstart import (
- ALTERNATIVE_CONFIG_NAME, list_modificator, main, post_process_input, prepare_content,
- QUICKSTART_CONF)
+from tox._quickstart import ALTERNATIVE_CONFIG_NAME, list_modificator, main, post_process_input
+from tox._quickstart import prepare_content, QUICKSTART_CONF
-ALL_PY_ENVS_AS_STRING = ', '.join(tox.PYTHON.QUICKSTART_PY_ENVS)
-ALL_PY_ENVS_WO_LAST_AS_STRING = ', '.join(tox.PYTHON.QUICKSTART_PY_ENVS[:-1])
+ALL_PY_ENVS_AS_STRING = ", ".join(tox.PYTHON.QUICKSTART_PY_ENVS)
+ALL_PY_ENVS_WO_LAST_AS_STRING = ", ".join(tox.PYTHON.QUICKSTART_PY_ENVS[:-1])
SIGNS_OF_SANITY = (
- 'tox.readthedocs.io', '[tox]', '[testenv]', 'envlist = ', 'deps =', 'commands =')
+ "tox.readthedocs.io", "[tox]", "[testenv]", "envlist = ", "deps =", "commands ="
+)
"""A bunch of elements to be expected in the generated config as marker for basic sanity"""
@@ -27,18 +27,18 @@ class _answers:
return "|".join(self._inputs)
def __call__(self, prompt):
- print("prompt: '%s'" % prompt)
+ print("prompt: '{}'".format(prompt))
try:
answer = self._inputs.pop(0)
- print("user answer: '%s'" % answer)
+ print("user answer: '{}'".format(answer))
return answer
except IndexError:
- pytest.fail("missing user answer for '%s'" % prompt)
+ pytest.fail("missing user answer for '{}'".format(prompt))
class _cnf:
"""Handle files and args for different test scenarios."""
- SOME_CONTENT = 'dontcare'
+ SOME_CONTENT = "dontcare"
def __init__(self, exists=False, names=None, pass_path=False):
self.original_name = tox.INFO.DEFAULT_CONFIG_NAME
@@ -51,21 +51,21 @@ class _cnf:
@property
def argv(self):
- argv = ['tox-quickstart']
+ argv = ["tox-quickstart"]
if self.pass_path:
argv.append(os.getcwd())
return argv
@property
def dpath(self):
- return os.getcwd() if self.pass_path else ''
+ return os.getcwd() if self.pass_path else ""
def create(self):
paths_to_create = {self._original_path}
for name in self.names[:-1]:
paths_to_create.add(os.path.join(self.dpath, name))
for path in paths_to_create:
- with open(path, 'w') as f:
+ with open(path, "w") as f:
f.write(self.SOME_CONTENT)
@property
@@ -105,109 +105,130 @@ class _cnf:
class _exp:
"""Holds test expectations and a user scenario description."""
- STANDARD_EPECTATIONS = [ALL_PY_ENVS_AS_STRING, 'pytest', 'pytest']
+ STANDARD_EPECTATIONS = [ALL_PY_ENVS_AS_STRING, "pytest", "pytest"]
def __init__(self, name, exp=None):
self.name = name
exp = exp or self.STANDARD_EPECTATIONS
# NOTE extra mangling here ensures formatting is the same in file and exp
- map_ = {'deps': list_modificator(exp[1]), 'commands': list_modificator(exp[2])}
+ map_ = {"deps": list_modificator(exp[1]), "commands": list_modificator(exp[2])}
post_process_input(map_)
- map_['envlist'] = exp[0]
+ map_["envlist"] = exp[0]
self.content = prepare_content(QUICKSTART_CONF.format(**map_))
def __str__(self):
return self.name
-@pytest.mark.usefixtures('work_in_clean_dir')
-@pytest.mark.parametrize(argnames='answers, exp, cnf', ids=lambda param: str(param), argvalues=(
+@pytest.mark.usefixtures("work_in_clean_dir")
+@pytest.mark.parametrize(
+ argnames="answers, exp, cnf",
+ ids=lambda param: str(param),
+ argvalues=(
(
- _answers([4, 'Y', 'Y', 'Y', 'Y', 'Y', 'N', 'pytest', 'pytest']),
- _exp('choose versions individually and use pytest',
- [ALL_PY_ENVS_WO_LAST_AS_STRING, 'pytest', 'pytest']),
+ _answers([4, "Y", "Y", "Y", "Y", "Y", "N", "pytest", "pytest"]),
+ _exp(
+ "choose versions individually and use pytest",
+ [ALL_PY_ENVS_WO_LAST_AS_STRING, "pytest", "pytest"],
+ ),
_cnf(),
),
(
- _answers([4, 'Y', 'Y', 'Y', 'Y', 'Y', 'N', 'py.test', '']),
- _exp('choose versions individually and use old fashioned py.test',
- [ALL_PY_ENVS_WO_LAST_AS_STRING, 'pytest', 'py.test']),
+ _answers([4, "Y", "Y", "Y", "Y", "Y", "N", "py.test", ""]),
+ _exp(
+ "choose versions individually and use old fashioned py.test",
+ [ALL_PY_ENVS_WO_LAST_AS_STRING, "pytest", "py.test"],
+ ),
_cnf(),
),
(
- _answers([1, 'pytest', '']),
- _exp('choose current release Python and pytest with defaut deps',
- [tox.PYTHON.CURRENT_RELEASE_ENV, 'pytest', 'pytest']),
+ _answers([1, "pytest", ""]),
+ _exp(
+ "choose current release Python and pytest with defaut deps",
+ [tox.PYTHON.CURRENT_RELEASE_ENV, "pytest", "pytest"],
+ ),
_cnf(),
),
(
- _answers([1, 'pytest -n auto', 'pytest-xdist']),
- _exp('choose current release Python and pytest with xdist and some args',
- [tox.PYTHON.CURRENT_RELEASE_ENV, 'pytest, pytest-xdist',
- 'pytest -n auto']),
+ _answers([1, "pytest -n auto", "pytest-xdist"]),
+ _exp(
+ "choose current release Python and pytest with xdist and some args",
+ [tox.PYTHON.CURRENT_RELEASE_ENV, "pytest, pytest-xdist", "pytest -n auto"],
+ ),
_cnf(),
),
(
- _answers([2, 'pytest', '']),
- _exp('choose py27, current release Python and pytest with defaut deps',
- ['py27, %s' % tox.PYTHON.CURRENT_RELEASE_ENV, 'pytest', 'pytest']),
+ _answers([2, "pytest", ""]),
+ _exp(
+ "choose py27, current release Python and pytest with defaut deps",
+ ["py27, {}".format(tox.PYTHON.CURRENT_RELEASE_ENV), "pytest", "pytest"],
+ ),
_cnf(),
),
(
- _answers([3, 'pytest', '']),
- _exp('choose all supported version and pytest with defaut deps'),
+ _answers([3, "pytest", ""]),
+ _exp("choose all supported version and pytest with defaut deps"),
_cnf(),
),
(
- _answers([4, 'Y', 'Y', 'Y', 'Y', 'Y', 'N', 'py.test', '']),
- _exp('choose versions individually and use old fashioned py.test',
- [ALL_PY_ENVS_WO_LAST_AS_STRING, 'pytest', 'py.test']),
+ _answers([4, "Y", "Y", "Y", "Y", "Y", "N", "py.test", ""]),
+ _exp(
+ "choose versions individually and use old fashioned py.test",
+ [ALL_PY_ENVS_WO_LAST_AS_STRING, "pytest", "py.test"],
+ ),
_cnf(),
),
(
- _answers([4, '', '', '', '', '', '', '', '']),
- _exp('choose no version individually and defaults'),
+ _answers([4, "", "", "", "", "", "", "", ""]),
+ _exp("choose no version individually and defaults"),
_cnf(),
),
(
- _answers([4, 'Y', 'Y', 'Y', 'Y', 'Y', 'N', 'python -m unittest discover', '']),
- _exp('choose versions individually and use nose with default deps',
- [ALL_PY_ENVS_WO_LAST_AS_STRING, '', 'python -m unittest discover']),
+ _answers([4, "Y", "Y", "Y", "Y", "Y", "N", "python -m unittest discover", ""]),
+ _exp(
+ "choose versions individually and use nose with default deps",
+ [ALL_PY_ENVS_WO_LAST_AS_STRING, "", "python -m unittest discover"],
+ ),
_cnf(),
),
(
- _answers([4, 'Y', 'Y', 'Y', 'Y', 'Y', 'N', 'nosetests', 'nose']),
- _exp('choose versions individually and use nose with default deps',
- [ALL_PY_ENVS_WO_LAST_AS_STRING, 'nose', 'nosetests']),
+ _answers([4, "Y", "Y", "Y", "Y", "Y", "N", "nosetests", "nose"]),
+ _exp(
+ "choose versions individually and use nose with default deps",
+ [ALL_PY_ENVS_WO_LAST_AS_STRING, "nose", "nosetests"],
+ ),
_cnf(),
),
(
- _answers([4, 'Y', 'Y', 'Y', 'Y', 'Y', 'N', 'trial', '']),
- _exp('choose versions individually and use twisted tests with default deps',
- [ALL_PY_ENVS_WO_LAST_AS_STRING, 'twisted', 'trial']),
+ _answers([4, "Y", "Y", "Y", "Y", "Y", "N", "trial", ""]),
+ _exp(
+ "choose versions individually and use twisted tests with default deps",
+ [ALL_PY_ENVS_WO_LAST_AS_STRING, "twisted", "trial"],
+ ),
_cnf(),
),
(
- _answers([4, '', '', '', '', '', '', '', '']),
- _exp('existing not overriden, generated to alternative with default name'),
+ _answers([4, "", "", "", "", "", "", "", ""]),
+ _exp("existing not overriden, generated to alternative with default name"),
_cnf(exists=True),
),
(
- _answers([4, '', '', '', '', '', '', '', '']),
- _exp('existing not overriden, generated to alternative with custom name'),
- _cnf(exists=True, names=['some-other.ini']),
+ _answers([4, "", "", "", "", "", "", "", ""]),
+ _exp("existing not overriden, generated to alternative with custom name"),
+ _cnf(exists=True, names=["some-other.ini"]),
),
(
- _answers([4, '', '', '', '', '', '', '', '']),
- _exp('existing not override, generated to alternative'),
- _cnf(exists=True, names=['tox.ini', 'some-other.ini']),
+ _answers([4, "", "", "", "", "", "", "", ""]),
+ _exp("existing not override, generated to alternative"),
+ _cnf(exists=True, names=["tox.ini", "some-other.ini"]),
),
(
- _answers([4, '', '', '', '', '', '', '', '']),
- _exp('existing alternatives are not overriden, generated to alternative'),
- _cnf(exists=True, names=['tox.ini', 'setup.py', 'some-other.ini']),
+ _answers([4, "", "", "", "", "", "", "", ""]),
+ _exp("existing alternatives are not overriden, generated to alternative"),
+ _cnf(exists=True, names=["tox.ini", "setup.py", "some-other.ini"]),
),
-))
+ ),
+)
def test_quickstart(answers, cnf, exp, monkeypatch):
"""Test quickstart script using some little helpers.
@@ -215,13 +236,13 @@ def test_quickstart(answers, cnf, exp, monkeypatch):
:param _cnf cnf: helper for args and config file paths and contents
:param _exp exp: expectation helper
"""
- monkeypatch.setattr('six.moves.input', answers)
- monkeypatch.setattr('sys.argv', cnf.argv)
+ monkeypatch.setattr("six.moves.input", answers)
+ monkeypatch.setattr("sys.argv", cnf.argv)
if cnf.exists:
answers.extend(cnf.names)
cnf.create()
main()
- print("generated config at %s:\n%s\n" % (cnf.path_to_generated, cnf.generated_content))
+ print("generated config at {}:\n{}\n".format(cnf.path_to_generated, cnf.generated_content))
check_basic_sanity(cnf.generated_content, SIGNS_OF_SANITY)
assert cnf.generated_content == exp.content
if cnf.exists:
@@ -231,4 +252,4 @@ def test_quickstart(answers, cnf, exp, monkeypatch):
def check_basic_sanity(content, signs):
for sign in signs:
if sign not in content:
- pytest.fail("%s not in\n%s" % (sign, content))
+ pytest.fail("{} not in\n{}".format(sign, content))
diff --git a/tests/test_result.py b/tests/test_result.py
index 924193fd..38f02bc1 100644
--- a/tests/test_result.py
+++ b/tests/test_result.py
@@ -39,10 +39,12 @@ def test_set_header(pkg):
assert replog.dict["toxversion"] == tox.__version__
assert replog.dict["platform"] == sys.platform
assert replog.dict["host"] == socket.getfqdn()
- assert replog.dict["installpkg"] == {
+ expected = {
"basename": "hello-1.0.tar.gz",
"md5": pkg.computehash("md5"),
- "sha256": pkg.computehash("sha256")}
+ "sha256": pkg.computehash("sha256"),
+ }
+ assert replog.dict["installpkg"] == expected
data = replog.dumps_json()
replog2 = ResultLog(data)
assert replog2.dict == replog.dict
@@ -65,31 +67,30 @@ def test_get_commandlog(pkg):
assert "setup" not in envlog.dict
setuplog = envlog.get_commandlog("setup")
setuplog.add_command(["virtualenv", "..."], "venv created", 0)
- assert setuplog.list == [{"command": ["virtualenv", "..."],
- "output": "venv created",
- "retcode": "0"}]
+ expected = [{"command": ["virtualenv", "..."], "output": "venv created", "retcode": "0"}]
+ assert setuplog.list == expected
assert envlog.dict["setup"]
setuplog2 = replog.get_envlog("py36").get_commandlog("setup")
assert setuplog2.list == setuplog.list
-@pytest.mark.parametrize('exit_code', [None, 0, 5, 128 + signal.SIGTERM, 1234])
-@pytest.mark.parametrize('os_name', ['posix', 'nt'])
+@pytest.mark.parametrize("exit_code", [None, 0, 5, 128 + signal.SIGTERM, 1234])
+@pytest.mark.parametrize("os_name", ["posix", "nt"])
def test_invocation_error(exit_code, os_name, mocker, monkeypatch):
- monkeypatch.setattr(os, 'name', value=os_name)
- mocker.spy(tox.exception, 'exit_code_str')
+ monkeypatch.setattr(os, "name", value=os_name)
+ mocker.spy(tox.exception, "exit_code_str")
result = str(tox.exception.InvocationError("<command>", exit_code=exit_code))
# check that mocker works, because it will be our only test in
# test_z_cmdline.py::test_exit_code needs the mocker.spy above
assert tox.exception.exit_code_str.call_count == 1
- assert tox.exception.exit_code_str.call_args == mocker.call(
- 'InvocationError', "<command>", exit_code)
+ call_args = tox.exception.exit_code_str.call_args
+ assert call_args == mocker.call("InvocationError", "<command>", exit_code)
if exit_code is None:
assert "(exited with code" not in result
else:
assert "(exited with code %d)" % exit_code in result
note = "Note: this might indicate a fatal error signal"
- if (os_name == 'posix') and (exit_code == 128 + signal.SIGTERM):
+ if (os_name == "posix") and (exit_code == 128 + signal.SIGTERM):
assert note in result
assert "({} - 128 = {}: SIGTERM)".format(exit_code, signal.SIGTERM) in result
else:
diff --git a/tests/test_venv.py b/tests/test_venv.py
index 912f03f6..0d7ec60a 100644
--- a/tests/test_venv.py
+++ b/tests/test_venv.py
@@ -7,8 +7,13 @@ import pytest
import tox
from tox.interpreters import NoInterpreterInfo
from tox.venv import (
- CreationConfig, VirtualEnv, getdigest, prepend_shebang_interpreter,
- tox_testenv_create, tox_testenv_install_deps)
+ CreationConfig,
+ VirtualEnv,
+ getdigest,
+ prepend_shebang_interpreter,
+ tox_testenv_create,
+ tox_testenv_install_deps,
+)
def test_getdigest(tmpdir):
@@ -16,21 +21,26 @@ def test_getdigest(tmpdir):
def test_getsupportedinterpreter(monkeypatch, newconfig, mocksession):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:python]
- basepython=%s
- """ % sys.executable)
- venv = VirtualEnv(config.envconfigs['python'], session=mocksession)
+ basepython={}
+ """.format(
+ sys.executable
+ ),
+ )
+ venv = VirtualEnv(config.envconfigs["python"], session=mocksession)
interp = venv.getsupportedinterpreter()
# realpath needed for debian symlinks
assert py.path.local(interp).realpath() == py.path.local(sys.executable).realpath()
- monkeypatch.setattr(tox.INFO, 'IS_WIN', True)
- monkeypatch.setattr(venv.envconfig, 'basepython', 'jython')
+ monkeypatch.setattr(tox.INFO, "IS_WIN", True)
+ monkeypatch.setattr(venv.envconfig, "basepython", "jython")
with pytest.raises(tox.exception.UnsupportedInterpreter):
venv.getsupportedinterpreter()
monkeypatch.undo()
monkeypatch.setattr(venv.envconfig, "envname", "py1")
- monkeypatch.setattr(venv.envconfig, 'basepython', 'notexistingpython')
+ monkeypatch.setattr(venv.envconfig, "basepython", "notexistingpython")
with pytest.raises(tox.exception.InterpreterNotFound):
venv.getsupportedinterpreter()
monkeypatch.undo()
@@ -43,10 +53,13 @@ def test_getsupportedinterpreter(monkeypatch, newconfig, mocksession):
def test_create(mocksession, newconfig):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:py123]
- """)
- envconfig = config.envconfigs['py123']
+ """,
+ )
+ envconfig = config.envconfigs["py123"]
venv = VirtualEnv(envconfig, session=mocksession)
assert venv.path == envconfig.envdir
assert not venv.path.check()
@@ -58,7 +71,8 @@ def test_create(mocksession, newconfig):
assert "virtualenv" == str(args[2])
if not tox.INFO.IS_WIN:
# realpath is needed for stuff like the debian symlinks
- assert py.path.local(sys.executable).realpath() == py.path.local(args[0]).realpath()
+ our_sys_path = py.path.local(sys.executable).realpath()
+ assert our_sys_path == py.path.local(args[0]).realpath()
# assert Envconfig.toxworkdir in args
assert venv.getcommandpath("easy_install", cwd=py.path.local())
interp = venv._getliveconfig().python
@@ -67,10 +81,13 @@ def test_create(mocksession, newconfig):
def test_commandpath_venv_precedence(tmpdir, monkeypatch, mocksession, newconfig):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:py123]
- """)
- envconfig = config.envconfigs['py123']
+ """,
+ )
+ envconfig = config.envconfigs["py123"]
venv = VirtualEnv(envconfig, session=mocksession)
tmpdir.ensure("easy_install")
monkeypatch.setenv("PATH", str(tmpdir), prepend=os.pathsep)
@@ -80,14 +97,17 @@ def test_commandpath_venv_precedence(tmpdir, monkeypatch, mocksession, newconfig
def test_create_sitepackages(mocksession, newconfig):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:site]
sitepackages=True
[testenv:nosite]
sitepackages=False
- """)
- envconfig = config.envconfigs['site']
+ """,
+ )
+ envconfig = config.envconfigs["site"]
venv = VirtualEnv(envconfig, session=mocksession)
action = mocksession.newaction(venv, "getenv")
tox_testenv_create(action=action, venv=venv)
@@ -97,7 +117,7 @@ def test_create_sitepackages(mocksession, newconfig):
assert "--system-site-packages" in map(str, args)
mocksession._clearmocks()
- envconfig = config.envconfigs['nosite']
+ envconfig = config.envconfigs["nosite"]
venv = VirtualEnv(envconfig, session=mocksession)
action = mocksession.newaction(venv, "getenv")
tox_testenv_create(action=action, venv=venv)
@@ -109,13 +129,16 @@ def test_create_sitepackages(mocksession, newconfig):
def test_install_deps_wildcard(newmocksession):
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[tox]
distshare = {toxworkdir}/distshare
[testenv:py123]
deps=
{distshare}/dep1-*
- """)
+ """,
+ )
venv = mocksession.getenv("py123")
action = mocksession.newaction(venv, "getenv")
tox_testenv_create(action=action, venv=venv)
@@ -136,7 +159,9 @@ def test_install_deps_wildcard(newmocksession):
def test_install_deps_indexserver(newmocksession):
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[tox]
indexserver =
abc = ABC
@@ -146,8 +171,9 @@ def test_install_deps_indexserver(newmocksession):
dep1
:abc:dep2
:abc2:dep3
- """)
- venv = mocksession.getenv('py123')
+ """,
+ )
+ venv = mocksession.getenv("py123")
action = mocksession.newaction(venv, "getenv")
tox_testenv_create(action=action, venv=venv)
pcalls = mocksession._pcalls
@@ -170,13 +196,16 @@ def test_install_deps_indexserver(newmocksession):
def test_install_deps_pre(newmocksession):
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv]
pip_pre=true
deps=
dep1
- """)
- venv = mocksession.getenv('python')
+ """,
+ )
+ venv = mocksession.getenv("python")
action = mocksession.newaction(venv, "getenv")
tox_testenv_create(action=action, venv=venv)
pcalls = mocksession._pcalls
@@ -191,12 +220,15 @@ def test_install_deps_pre(newmocksession):
def test_installpkg_indexserver(newmocksession, tmpdir):
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[tox]
indexserver =
default = ABC
- """)
- venv = mocksession.getenv('python')
+ """,
+ )
+ venv = mocksession.getenv("python")
pcalls = mocksession._pcalls
p = tmpdir.ensure("distfile.tar.gz")
mocksession.installpkg(venv, p)
@@ -208,11 +240,14 @@ def test_installpkg_indexserver(newmocksession, tmpdir):
def test_install_recreate(newmocksession, tmpdir):
pkg = tmpdir.ensure("package.tar.gz")
- mocksession = newmocksession(['--recreate'], """
+ mocksession = newmocksession(
+ ["--recreate"],
+ """
[testenv]
deps=xyz
- """)
- venv = mocksession.getenv('python')
+ """,
+ )
+ venv = mocksession.getenv("python")
action = mocksession.newaction(venv, "update")
venv.update(action)
@@ -223,29 +258,35 @@ def test_install_recreate(newmocksession, tmpdir):
def test_install_sdist_extras(newmocksession):
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv]
extras = testing
development
- """)
- venv = mocksession.getenv('python')
+ """,
+ )
+ venv = mocksession.getenv("python")
action = mocksession.newaction(venv, "getenv")
tox_testenv_create(action=action, venv=venv)
pcalls = mocksession._pcalls
assert len(pcalls) == 1
pcalls[:] = []
- venv.installpkg('distfile.tar.gz', action=action)
- assert 'distfile.tar.gz[testing,development]' in pcalls[-1].args
+ venv.installpkg("distfile.tar.gz", action=action)
+ assert "distfile.tar.gz[testing,development]" in pcalls[-1].args
def test_develop_extras(newmocksession, tmpdir):
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv]
extras = testing
development
- """)
- venv = mocksession.getenv('python')
+ """,
+ )
+ venv = mocksession.getenv("python")
action = mocksession.newaction(venv, "getenv")
tox_testenv_create(action=action, venv=venv)
pcalls = mocksession._pcalls
@@ -253,7 +294,7 @@ def test_develop_extras(newmocksession, tmpdir):
pcalls[:] = []
venv.developpkg(tmpdir, action=action)
- expected = "%s[testing,development]" % tmpdir.strpath
+ expected = "{}[testing,development]".format(tmpdir.strpath)
assert expected in pcalls[-1].args
@@ -261,14 +302,17 @@ def test_env_variables_added_to_needs_reinstall(tmpdir, mocksession, newconfig,
tmpdir.ensure("setup.py")
monkeypatch.setenv("TEMP_PASS_VAR", "123")
monkeypatch.setenv("TEMP_NOPASS_VAR", "456")
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:python]
passenv = temp_pass_var
setenv =
CUSTOM_VAR = 789
- """)
+ """,
+ )
- venv = VirtualEnv(config.envconfigs['python'], session=mocksession)
+ venv = VirtualEnv(config.envconfigs["python"], session=mocksession)
action = mocksession.newaction(venv, "hello")
venv._needs_reinstall(tmpdir, action)
@@ -278,24 +322,24 @@ def test_env_variables_added_to_needs_reinstall(tmpdir, mocksession, newconfig,
env = pcalls[0].env
# should have access to setenv vars
- assert 'CUSTOM_VAR' in env
- assert env['CUSTOM_VAR'] == '789'
+ assert "CUSTOM_VAR" in env
+ assert env["CUSTOM_VAR"] == "789"
# should have access to passenv vars
- assert 'TEMP_PASS_VAR' in env
- assert env['TEMP_PASS_VAR'] == "123"
+ assert "TEMP_PASS_VAR" in env
+ assert env["TEMP_PASS_VAR"] == "123"
# should also have access to full invocation environment,
# for backward compatibility, and to match behavior of venv.run_install_command()
- assert 'TEMP_NOPASS_VAR' in env
+ assert "TEMP_NOPASS_VAR" in env
assert env["TEMP_NOPASS_VAR"] == "456"
def test_test_hashseed_is_in_output(newmocksession, monkeypatch):
- seed = '123456789'
- monkeypatch.setattr('tox.config.make_hashseed', lambda: seed)
+ seed = "123456789"
+ monkeypatch.setattr("tox.config.make_hashseed", lambda: seed)
mocksession = newmocksession([], "")
- venv = mocksession.getenv('python')
+ venv = mocksession.getenv("python")
action = mocksession.newaction(venv, "update")
venv.update(action)
venv.test()
@@ -303,11 +347,14 @@ def test_test_hashseed_is_in_output(newmocksession, monkeypatch):
def test_test_runtests_action_command_is_in_output(newmocksession):
- mocksession = newmocksession([], '''
+ mocksession = newmocksession(
+ [],
+ """
[testenv]
commands = echo foo bar
- ''')
- venv = mocksession.getenv('python')
+ """,
+ )
+ venv = mocksession.getenv("python")
action = mocksession.newaction(venv, "update")
venv.update(action)
venv.test()
@@ -315,74 +362,88 @@ def test_test_runtests_action_command_is_in_output(newmocksession):
def test_install_error(newmocksession):
- mocksession = newmocksession(['--recreate'], """
+ mocksession = newmocksession(
+ ["--recreate"],
+ """
[testenv]
deps=xyz
commands=
qwelkqw
- """)
- venv = mocksession.getenv('python')
+ """,
+ )
+ venv = mocksession.getenv("python")
venv.test()
mocksession.report.expect("error", "*not find*qwelkqw*")
assert venv.status == "commands failed"
def test_install_command_not_installed(newmocksession):
- mocksession = newmocksession(['--recreate'], """
+ mocksession = newmocksession(
+ ["--recreate"],
+ """
[testenv]
commands=
pytest
- """)
- venv = mocksession.getenv('python')
+ """,
+ )
+ venv = mocksession.getenv("python")
venv.test()
mocksession.report.expect("warning", "*test command found but not*")
assert venv.status == 0
def test_install_command_whitelisted(newmocksession):
- mocksession = newmocksession(['--recreate'], """
+ mocksession = newmocksession(
+ ["--recreate"],
+ """
[testenv]
whitelist_externals = pytest
xy*
commands=
pytest
xyz
- """)
- venv = mocksession.getenv('python')
+ """,
+ )
+ venv = mocksession.getenv("python")
venv.test()
- mocksession.report.expect("warning", "*test command found but not*",
- invert=True)
+ mocksession.report.expect("warning", "*test command found but not*", invert=True)
assert venv.status == "commands failed"
def test_install_command_not_installed_bash(newmocksession):
- mocksession = newmocksession(['--recreate'], """
+ mocksession = newmocksession(
+ ["--recreate"],
+ """
[testenv]
commands=
bash
- """)
- venv = mocksession.getenv('python')
+ """,
+ )
+ venv = mocksession.getenv("python")
venv.test()
mocksession.report.expect("warning", "*test command found but not*")
def test_install_python3(newmocksession):
- if not py.path.local.sysfind('python3'):
+ if not py.path.local.sysfind("python3"):
pytest.skip("needs python3")
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv:py123]
basepython=python3
deps=
dep1
dep2
- """)
- venv = mocksession.getenv('py123')
+ """,
+ )
+ venv = mocksession.getenv("py123")
action = mocksession.newaction(venv, "getenv")
tox_testenv_create(action=action, venv=venv)
pcalls = mocksession._pcalls
assert len(pcalls) == 1
args = pcalls[0].args
- assert str(args[2]) == 'virtualenv'
+ assert str(args[2]) == "virtualenv"
pcalls[:] = []
action = mocksession.newaction(venv, "hello")
venv._install(["hello"], action=action)
@@ -394,9 +455,10 @@ def test_install_python3(newmocksession):
class TestCreationConfig:
+
def test_basic(self, newconfig, mocksession, tmpdir):
config = newconfig([], "")
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
venv = VirtualEnv(envconfig, session=mocksession)
cconfig = venv._getliveconfig()
assert cconfig.matches(cconfig)
@@ -407,33 +469,42 @@ class TestCreationConfig:
assert cconfig.matches(newconfig)
def test_matchingdependencies(self, newconfig, mocksession):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv]
deps=abc
- """)
- envconfig = config.envconfigs['python']
+ """,
+ )
+ envconfig = config.envconfigs["python"]
venv = VirtualEnv(envconfig, session=mocksession)
cconfig = venv._getliveconfig()
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv]
deps=xyz
- """)
- envconfig = config.envconfigs['python']
+ """,
+ )
+ envconfig = config.envconfigs["python"]
venv = VirtualEnv(envconfig, session=mocksession)
otherconfig = venv._getliveconfig()
assert not cconfig.matches(otherconfig)
def test_matchingdependencies_file(self, newconfig, mocksession):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[tox]
distshare={toxworkdir}/distshare
[testenv]
deps=abc
{distshare}/xyz.zip
- """)
+ """,
+ )
xyz = config.distshare.join("xyz.zip")
xyz.ensure()
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
venv = VirtualEnv(envconfig, session=mocksession)
cconfig = venv._getliveconfig()
assert cconfig.matches(cconfig)
@@ -442,15 +513,18 @@ class TestCreationConfig:
assert not cconfig.matches(newconfig)
def test_matchingdependencies_latest(self, newconfig, mocksession):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[tox]
distshare={toxworkdir}/distshare
[testenv]
deps={distshare}/xyz-*
- """)
+ """,
+ )
config.distshare.ensure("xyz-1.2.0.zip")
xyz2 = config.distshare.ensure("xyz-1.2.1.zip")
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
venv = VirtualEnv(envconfig, session=mocksession)
cconfig = venv._getliveconfig()
md5, path = cconfig.deps[0]
@@ -460,7 +534,7 @@ class TestCreationConfig:
def test_python_recreation(self, tmpdir, newconfig, mocksession):
pkg = tmpdir.ensure("package.tar.gz")
config = newconfig([], "")
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
venv = VirtualEnv(envconfig, session=mocksession)
cconfig = venv._getliveconfig()
action = mocksession.newaction(venv, "update")
@@ -470,7 +544,7 @@ class TestCreationConfig:
assert venv.path_config.check()
assert mocksession._pcalls
args1 = map(str, mocksession._pcalls[0].args)
- assert 'virtualenv' in " ".join(args1)
+ assert "virtualenv" in " ".join(args1)
mocksession.report.expect("*", "*create*")
# modify config and check that recreation happens
mocksession._clearmocks()
@@ -486,7 +560,7 @@ class TestCreationConfig:
def test_dep_recreation(self, newconfig, mocksession):
config = newconfig([], "")
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
venv = VirtualEnv(envconfig, session=mocksession)
action = mocksession.newaction(venv, "update")
venv.update(action)
@@ -500,7 +574,7 @@ class TestCreationConfig:
def test_develop_recreation(self, newconfig, mocksession):
config = newconfig([], "")
- envconfig = config.envconfigs['python']
+ envconfig = config.envconfigs["python"]
venv = VirtualEnv(envconfig, session=mocksession)
action = mocksession.newaction(venv, "update")
venv.update(action)
@@ -514,69 +588,81 @@ class TestCreationConfig:
class TestVenvTest:
+
def test_envbindir_path(self, newmocksession, monkeypatch):
monkeypatch.setenv("PIP_RESPECT_VIRTUALENV", "1")
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv:python]
commands=abc
- """)
+ """,
+ )
venv = mocksession.getenv("python")
action = mocksession.newaction(venv, "getenv")
monkeypatch.setenv("PATH", "xyz")
sysfind_calls = []
- monkeypatch.setattr("py.path.local.sysfind", classmethod(
- lambda *args, **kwargs: sysfind_calls.append(kwargs) or 0 / 0))
+ monkeypatch.setattr(
+ "py.path.local.sysfind",
+ classmethod(lambda *args, **kwargs: sysfind_calls.append(kwargs) or 0 / 0),
+ )
with pytest.raises(ZeroDivisionError):
- venv._install(list('123'), action=action)
+ venv._install(list("123"), action=action)
assert sysfind_calls.pop()["paths"] == [venv.envconfig.envbindir]
with pytest.raises(ZeroDivisionError):
venv.test(action)
assert sysfind_calls.pop()["paths"] == [venv.envconfig.envbindir]
with pytest.raises(ZeroDivisionError):
- venv.run_install_command(['qwe'], action=action)
+ venv.run_install_command(["qwe"], action=action)
assert sysfind_calls.pop()["paths"] == [venv.envconfig.envbindir]
monkeypatch.setenv("PIP_RESPECT_VIRTUALENV", "1")
monkeypatch.setenv("PIP_REQUIRE_VIRTUALENV", "1")
monkeypatch.setenv("__PYVENV_LAUNCHER__", "1")
with pytest.raises(ZeroDivisionError):
- venv.run_install_command(['qwe'], action=action)
- assert 'PIP_RESPECT_VIRTUALENV' not in os.environ
- assert 'PIP_REQUIRE_VIRTUALENV' not in os.environ
- assert '__PYVENV_LAUNCHER__' not in os.environ
+ venv.run_install_command(["qwe"], action=action)
+ assert "PIP_RESPECT_VIRTUALENV" not in os.environ
+ assert "PIP_REQUIRE_VIRTUALENV" not in os.environ
+ assert "__PYVENV_LAUNCHER__" not in os.environ
def test_pythonpath_usage(self, newmocksession, monkeypatch):
monkeypatch.setenv("PYTHONPATH", "/my/awesome/library")
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv:python]
commands=abc
- """)
+ """,
+ )
venv = mocksession.getenv("python")
action = mocksession.newaction(venv, "getenv")
- venv.run_install_command(['qwe'], action=action)
- assert 'PYTHONPATH' not in os.environ
+ venv.run_install_command(["qwe"], action=action)
+ assert "PYTHONPATH" not in os.environ
mocksession.report.expect("warning", "*Discarding $PYTHONPATH from environment*")
pcalls = mocksession._pcalls
assert len(pcalls) == 1
- assert 'PYTHONPATH' not in pcalls[0].env
+ assert "PYTHONPATH" not in pcalls[0].env
# passenv = PYTHONPATH allows PYTHONPATH to stay in environment
monkeypatch.setenv("PYTHONPATH", "/my/awesome/library")
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv:python]
commands=abc
passenv = PYTHONPATH
- """)
+ """,
+ )
venv = mocksession.getenv("python")
action = mocksession.newaction(venv, "getenv")
- venv.run_install_command(['qwe'], action=action)
- assert 'PYTHONPATH' in os.environ
+ venv.run_install_command(["qwe"], action=action)
+ assert "PYTHONPATH" in os.environ
mocksession.report.not_expect("warning", "*Discarding $PYTHONPATH from environment*")
pcalls = mocksession._pcalls
assert len(pcalls) == 2
- assert pcalls[1].env['PYTHONPATH'] == '/my/awesome/library'
+ assert pcalls[1].env["PYTHONPATH"] == "/my/awesome/library"
# FIXME this test fails when run in isolation - find what this depends on
@@ -585,17 +671,20 @@ def test_env_variables_added_to_pcall(tmpdir, mocksession, newconfig, monkeypatc
pkg = tmpdir.ensure("package.tar.gz")
monkeypatch.setenv("X123", "123")
monkeypatch.setenv("YY", "456")
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:python]
commands=python -V
passenv = x123
setenv =
ENV_VAR = value
PYTHONPATH = value
- """)
+ """,
+ )
mocksession._clearmocks()
- venv = VirtualEnv(config.envconfigs['python'], session=mocksession)
+ venv = VirtualEnv(config.envconfigs["python"], session=mocksession)
mocksession.installpkg(venv, pkg)
venv.test()
@@ -604,18 +693,17 @@ def test_env_variables_added_to_pcall(tmpdir, mocksession, newconfig, monkeypatc
for x in pcalls:
env = x.env
assert env is not None
- assert 'ENV_VAR' in env
- assert env['ENV_VAR'] == 'value'
- assert env['VIRTUAL_ENV'] == str(venv.path)
- assert env['X123'] == "123"
- assert 'PYTHONPATH' in env
- assert env['PYTHONPATH'] == 'value'
+ assert "ENV_VAR" in env
+ assert env["ENV_VAR"] == "value"
+ assert env["VIRTUAL_ENV"] == str(venv.path)
+ assert env["X123"] == "123"
+ assert "PYTHONPATH" in env
+ assert env["PYTHONPATH"] == "value"
# all env variables are passed for installation
assert pcalls[0].env["YY"] == "456"
assert "YY" not in pcalls[1].env
- assert {"ENV_VAR", "VIRTUAL_ENV", "PYTHONHASHSEED", "X123", "PATH"} \
- .issubset(pcalls[1].env)
+ assert {"ENV_VAR", "VIRTUAL_ENV", "PYTHONHASHSEED", "X123", "PATH"}.issubset(pcalls[1].env)
# setenv does not trigger PYTHONPATH warnings
mocksession.report.not_expect("warning", "*Discarding $PYTHONPATH from environment*")
@@ -627,64 +715,70 @@ def test_env_variables_added_to_pcall(tmpdir, mocksession, newconfig, monkeypatc
def test_installpkg_no_upgrade(tmpdir, newmocksession):
pkg = tmpdir.ensure("package.tar.gz")
mocksession = newmocksession([], "")
- venv = mocksession.getenv('python')
+ venv = mocksession.getenv("python")
venv.just_created = True
venv.envconfig.envdir.ensure(dir=1)
mocksession.installpkg(venv, pkg)
pcalls = mocksession._pcalls
assert len(pcalls) == 1
- assert '-U' not in pcalls[0].args
+ assert "-U" not in pcalls[0].args
def test_installpkg_upgrade(newmocksession, tmpdir):
pkg = tmpdir.ensure("package.tar.gz")
mocksession = newmocksession([], "")
- venv = mocksession.getenv('python')
- assert not hasattr(venv, 'just_created')
+ venv = mocksession.getenv("python")
+ assert not hasattr(venv, "just_created")
mocksession.installpkg(venv, pkg)
pcalls = mocksession._pcalls
assert len(pcalls) == 1
index = pcalls[0].args.index(str(pkg))
assert index >= 0
- assert '-U' in pcalls[0].args[:index]
- assert '--no-deps' in pcalls[0].args[:index]
+ assert "-U" in pcalls[0].args[:index]
+ assert "--no-deps" in pcalls[0].args[:index]
def test_run_install_command(newmocksession):
mocksession = newmocksession([], "")
- venv = mocksession.getenv('python')
+ venv = mocksession.getenv("python")
venv.just_created = True
venv.envconfig.envdir.ensure(dir=1)
action = mocksession.newaction(venv, "hello")
venv.run_install_command(packages=["whatever"], action=action)
pcalls = mocksession._pcalls
assert len(pcalls) == 1
- assert 'pip' in pcalls[0].args[0]
- assert 'install' in pcalls[0].args
+ assert "pip" in pcalls[0].args[0]
+ assert "install" in pcalls[0].args
env = pcalls[0].env
assert env is not None
def test_run_custom_install_command(newmocksession):
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv]
install_command=easy_install {opts} {packages}
- """)
- venv = mocksession.getenv('python')
+ """,
+ )
+ venv = mocksession.getenv("python")
venv.just_created = True
venv.envconfig.envdir.ensure(dir=1)
action = mocksession.newaction(venv, "hello")
venv.run_install_command(packages=["whatever"], action=action)
pcalls = mocksession._pcalls
assert len(pcalls) == 1
- assert 'easy_install' in pcalls[0].args[0]
- assert pcalls[0].args[1:] == ['whatever']
+ assert "easy_install" in pcalls[0].args[0]
+ assert pcalls[0].args[1:] == ["whatever"]
def test_command_relative_issue36(newmocksession, tmpdir, monkeypatch):
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv]
- """)
+ """,
+ )
x = tmpdir.ensure("x")
venv = mocksession.getenv("python")
x2 = venv.getcommandpath("./x", cwd=tmpdir)
@@ -695,28 +789,31 @@ def test_command_relative_issue36(newmocksession, tmpdir, monkeypatch):
mocksession.report.not_expect("warning", "*test command found but not*")
monkeypatch.setenv("PATH", str(tmpdir))
x4 = venv.getcommandpath("x", cwd=tmpdir)
- assert x4.endswith(os.sep + 'x')
+ assert x4.endswith(os.sep + "x")
mocksession.report.expect("warning", "*test command found but not*")
def test_ignore_outcome_failing_cmd(newmocksession):
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv]
commands=testenv_fail
ignore_outcome=True
- """)
+ """,
+ )
- venv = mocksession.getenv('python')
+ venv = mocksession.getenv("python")
venv.test()
assert venv.status == "ignored failed command"
- mocksession.report.expect("warning", "*command failed but result from "
- "testenv is ignored*")
+ mocksession.report.expect("warning", "*command failed but result from testenv is ignored*")
def test_tox_testenv_create(newmocksession):
log = []
class Plugin:
+
@tox.hookimpl
def tox_testenv_create(self, action, venv):
assert isinstance(action, tox.session.Action)
@@ -729,13 +826,17 @@ def test_tox_testenv_create(newmocksession):
assert isinstance(venv, VirtualEnv)
log.append(2)
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv]
commands=testenv_fail
ignore_outcome=True
- """, plugins=[Plugin()])
+ """,
+ plugins=[Plugin()],
+ )
- venv = mocksession.getenv('python')
+ venv = mocksession.getenv("python")
venv.update(action=mocksession.newaction(venv, "getenv"))
assert log == [1, 2]
@@ -744,126 +845,135 @@ def test_tox_testenv_pre_post(newmocksession):
log = []
class Plugin:
+
@tox.hookimpl
def tox_runtest_pre(self):
- log.append('started')
+ log.append("started")
@tox.hookimpl
def tox_runtest_post(self):
- log.append('finished')
+ log.append("finished")
- mocksession = newmocksession([], """
+ mocksession = newmocksession(
+ [],
+ """
[testenv]
commands=testenv_fail
- """, plugins=[Plugin()])
+ """,
+ plugins=[Plugin()],
+ )
- venv = mocksession.getenv('python')
+ venv = mocksession.getenv("python")
venv.status = None
assert log == []
mocksession.runtestenv(venv)
- assert log == ['started', 'finished']
+ assert log == ["started", "finished"]
@pytest.mark.skipif("sys.platform == 'win32'")
def test_tox_testenv_interpret_shebang_empty_instance(tmpdir):
- testfile = tmpdir.join('check_shebang_empty_instance.py')
- base_args = [str(testfile), 'arg1', 'arg2', 'arg3']
+ testfile = tmpdir.join("check_shebang_empty_instance.py")
+ base_args = [str(testfile), "arg1", "arg2", "arg3"]
# empty instance
- testfile.write('')
+ testfile.write("")
args = prepend_shebang_interpreter(base_args)
assert args == base_args
@pytest.mark.skipif("sys.platform == 'win32'")
def test_tox_testenv_interpret_shebang_empty_interpreter(tmpdir):
- testfile = tmpdir.join('check_shebang_empty_interpreter.py')
- base_args = [str(testfile), 'arg1', 'arg2', 'arg3']
+ testfile = tmpdir.join("check_shebang_empty_interpreter.py")
+ base_args = [str(testfile), "arg1", "arg2", "arg3"]
# empty interpreter
- testfile.write('#!')
+ testfile.write("#!")
args = prepend_shebang_interpreter(base_args)
assert args == base_args
@pytest.mark.skipif("sys.platform == 'win32'")
def test_tox_testenv_interpret_shebang_empty_interpreter_ws(tmpdir):
- testfile = tmpdir.join('check_shebang_empty_interpreter_ws.py')
- base_args = [str(testfile), 'arg1', 'arg2', 'arg3']
+ testfile = tmpdir.join("check_shebang_empty_interpreter_ws.py")
+ base_args = [str(testfile), "arg1", "arg2", "arg3"]
# empty interpreter (whitespaces)
- testfile.write('#! \n')
+ testfile.write("#! \n")
args = prepend_shebang_interpreter(base_args)
assert args == base_args
@pytest.mark.skipif("sys.platform == 'win32'")
def test_tox_testenv_interpret_shebang_interpreter_simple(tmpdir):
- testfile = tmpdir.join('check_shebang_interpreter_simple.py')
- base_args = [str(testfile), 'arg1', 'arg2', 'arg3']
+ testfile = tmpdir.join("check_shebang_interpreter_simple.py")
+ base_args = [str(testfile), "arg1", "arg2", "arg3"]
# interpreter (simple)
- testfile.write('#!interpreter')
+ testfile.write("#!interpreter")
args = prepend_shebang_interpreter(base_args)
- assert args == [b'interpreter'] + base_args
+ assert args == [b"interpreter"] + base_args
@pytest.mark.skipif("sys.platform == 'win32'")
def test_tox_testenv_interpret_shebang_interpreter_ws(tmpdir):
- testfile = tmpdir.join('check_shebang_interpreter_ws.py')
- base_args = [str(testfile), 'arg1', 'arg2', 'arg3']
+ testfile = tmpdir.join("check_shebang_interpreter_ws.py")
+ base_args = [str(testfile), "arg1", "arg2", "arg3"]
# interpreter (whitespaces)
- testfile.write('#! interpreter \n\n')
+ testfile.write("#! interpreter \n\n")
args = prepend_shebang_interpreter(base_args)
- assert args == [b'interpreter'] + base_args
+ assert args == [b"interpreter"] + base_args
@pytest.mark.skipif("sys.platform == 'win32'")
def test_tox_testenv_interpret_shebang_interpreter_arg(tmpdir):
- testfile = tmpdir.join('check_shebang_interpreter_arg.py')
- base_args = [str(testfile), 'arg1', 'arg2', 'arg3']
+ testfile = tmpdir.join("check_shebang_interpreter_arg.py")
+ base_args = [str(testfile), "arg1", "arg2", "arg3"]
# interpreter with argument
- testfile.write('#!interpreter argx\n')
+ testfile.write("#!interpreter argx\n")
args = prepend_shebang_interpreter(base_args)
- assert args == [b'interpreter', b'argx'] + base_args
+ assert args == [b"interpreter", b"argx"] + base_args
@pytest.mark.skipif("sys.platform == 'win32'")
def test_tox_testenv_interpret_shebang_interpreter_args(tmpdir):
- testfile = tmpdir.join('check_shebang_interpreter_args.py')
- base_args = [str(testfile), 'arg1', 'arg2', 'arg3']
+ testfile = tmpdir.join("check_shebang_interpreter_args.py")
+ base_args = [str(testfile), "arg1", "arg2", "arg3"]
# interpreter with argument (ensure single argument)
- testfile.write('#!interpreter argx argx-part2\n')
+ testfile.write("#!interpreter argx argx-part2\n")
args = prepend_shebang_interpreter(base_args)
- assert args == [b'interpreter', b'argx argx-part2'] + base_args
+ assert args == [b"interpreter", b"argx argx-part2"] + base_args
@pytest.mark.skipif("sys.platform == 'win32'")
def test_tox_testenv_interpret_shebang_real(tmpdir):
- testfile = tmpdir.join('check_shebang_real.py')
- base_args = [str(testfile), 'arg1', 'arg2', 'arg3']
+ testfile = tmpdir.join("check_shebang_real.py")
+ base_args = [str(testfile), "arg1", "arg2", "arg3"]
# interpreter (real example)
- testfile.write('#!/usr/bin/env python\n')
+ testfile.write("#!/usr/bin/env python\n")
args = prepend_shebang_interpreter(base_args)
- assert args == [b'/usr/bin/env', b'python'] + base_args
+ assert args == [b"/usr/bin/env", b"python"] + base_args
@pytest.mark.skipif("sys.platform == 'win32'")
def test_tox_testenv_interpret_shebang_long_example(tmpdir):
- testfile = tmpdir.join('check_shebang_long_example.py')
- base_args = [str(testfile), 'arg1', 'arg2', 'arg3']
+ testfile = tmpdir.join("check_shebang_long_example.py")
+ base_args = [str(testfile), "arg1", "arg2", "arg3"]
# interpreter (long example)
testfile.write(
- '#!this-is-an-example-of-a-very-long-interpret-directive-what-should-'
- 'be-directly-invoked-when-tox-needs-to-invoked-the-provided-script-'
- 'name-in-the-argument-list')
+ "#!this-is-an-example-of-a-very-long-interpret-directive-what-should-"
+ "be-directly-invoked-when-tox-needs-to-invoked-the-provided-script-"
+ "name-in-the-argument-list"
+ )
args = prepend_shebang_interpreter(base_args)
- assert args == [
- b'this-is-an-example-of-a-very-long-interpret-directive-what-should-be-'
- b'directly-invoked-when-tox-needs-to-invoked-the-provided-script-name-'
- b'in-the-argument-list'] + base_args
+ expected = [
+ b"this-is-an-example-of-a-very-long-interpret-directive-what-should-be-"
+ b"directly-invoked-when-tox-needs-to-invoked-the-provided-script-name-"
+ b"in-the-argument-list"
+ ]
+
+ assert args == expected + base_args
diff --git a/tests/test_z_cmdline.py b/tests/test_z_cmdline.py
index 18bcc98b..3419339a 100644
--- a/tests/test_z_cmdline.py
+++ b/tests/test_z_cmdline.py
@@ -18,12 +18,16 @@ pytest_plugins = "pytester"
def test_report_protocol(newconfig):
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[testenv:mypython]
deps=xy
- """)
+ """,
+ )
class Popen:
+
def __init__(self, *args, **kwargs):
pass
@@ -78,12 +82,16 @@ def test__resolve_pkg_doubledash(tmpdir, mocksession):
class TestSession:
+
def test_make_sdist(self, initproj):
- initproj("example123-0.5", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
- '''
- })
+ initproj(
+ "example123-0.5",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
+ """,
+ },
+ )
config = parseconfig([])
session = Session(config)
sdist = session.get_installpkg_path()
@@ -100,13 +108,18 @@ class TestSession:
def test_make_sdist_distshare(self, tmpdir, initproj):
distshare = tmpdir.join("distshare")
- initproj("example123-0.6", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
+ initproj(
+ "example123-0.6",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
[tox]
- distshare=%s
- ''' % distshare
- })
+ distshare={}
+ """.format(
+ distshare
+ ),
+ },
+ )
config = parseconfig([])
session = Session(config)
sdist = session.get_installpkg_path()
@@ -121,19 +134,22 @@ class TestSession:
mocksession.config.logdir.ensure(dir=1)
assert not mocksession.config.logdir.listdir()
action = mocksession.newaction(None, "something")
- action.popen(["echo", ])
+ action.popen(["echo"])
match = mocksession.report.getnext("logpopen")
assert match[1].outpath.relto(mocksession.config.logdir)
assert match[1].shell is False
def test_summary_status(self, initproj, capfd):
- initproj("logexample123-0.5", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
+ initproj(
+ "logexample123-0.5",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
[testenv:hello]
[testenv:world]
- '''
- })
+ """,
+ },
+ )
config = parseconfig([])
session = Session(config)
envs = session.venvlist
@@ -145,19 +161,22 @@ class TestSession:
assert not env2.status
session._summary()
out, err = capfd.readouterr()
- exp = "%s: FAIL XYZ" % env1.envconfig.envname
+ exp = "{}: FAIL XYZ".format(env1.envconfig.envname)
assert exp in out
- exp = "%s: commands succeeded" % env2.envconfig.envname
+ exp = "{}: commands succeeded".format(env2.envconfig.envname)
assert exp in out
def test_getvenv(self, initproj):
- initproj("logexample123-0.5", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
+ initproj(
+ "logexample123-0.5",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
[testenv:hello]
[testenv:world]
- '''
- })
+ """,
+ },
+ )
config = parseconfig([])
session = Session(config)
venv1 = session.getvenv("hello")
@@ -171,78 +190,90 @@ class TestSession:
def test_minversion(cmd, initproj):
- initproj("interp123-0.5", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
+ initproj(
+ "interp123-0.5",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
[tox]
minversion = 6.0
- '''
- })
+ """,
+ },
+ )
result = cmd("-v")
- assert re.match(r'ERROR: MinVersionError: tox version is .*,'
- r' required is at least 6.0', result.out)
+ assert re.match(
+ r"ERROR: MinVersionError: tox version is .*," r" required is at least 6.0", result.out
+ )
assert result.ret
def test_notoxini_help_still_works(initproj, cmd):
- initproj("example123-0.5", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- })
+ initproj("example123-0.5", filedefs={"tests": {"test_hello.py": "def test_hello(): pass"}})
result = cmd("-h")
assert result.err == "ERROR: toxini file 'tox.ini' not found\n"
- assert result.out.startswith('usage: ')
- assert any('--help' in l for l in result.outlines)
+ assert result.out.startswith("usage: ")
+ assert any("--help" in l for l in result.outlines), result.outlines
assert not result.ret
def test_notoxini_help_ini_still_works(initproj, cmd):
- initproj("example123-0.5", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- })
+ initproj("example123-0.5", filedefs={"tests": {"test_hello.py": "def test_hello(): pass"}})
result = cmd("--help-ini")
- assert any('setenv' in l for l in result.outlines)
+ assert any("setenv" in l for l in result.outlines), result.outlines
assert not result.ret
def test_envdir_equals_toxini_errors_out(cmd, initproj):
- initproj("interp123-0.7", filedefs={
- 'tox.ini': '''
+ initproj(
+ "interp123-0.7",
+ filedefs={
+ "tox.ini": """
[testenv]
envdir={toxinidir}
- '''
- })
+ """
+ },
+ )
result = cmd()
assert result.outlines[1] == "ERROR: ConfigError: envdir must not equal toxinidir"
- assert re.match(r'ERROR: venv \'python\' in .* would delete project', result.outlines[0])
+ assert re.match(r"ERROR: venv \'python\' in .* would delete project", result.outlines[0])
assert result.ret
def test_run_custom_install_command_error(cmd, initproj):
- initproj("interp123-0.5", filedefs={
- 'tox.ini': '''
+ initproj(
+ "interp123-0.5",
+ filedefs={
+ "tox.ini": """
[testenv]
install_command=./tox.ini {opts} {packages}
- '''
- })
+ """
+ },
+ )
result = cmd()
- assert re.match(r"ERROR: invocation failed \(errno \d+\), args: \['.*[/\\]tox\.ini",
- result.outlines[-1])
+ assert re.match(
+ r"ERROR: invocation failed \(errno \d+\), args: \['.*[/\\]tox\.ini", result.outlines[-1]
+ )
assert result.ret
def test_unknown_interpreter_and_env(cmd, initproj):
- initproj("interp123-0.5", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
+ initproj(
+ "interp123-0.5",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
[testenv:python]
basepython=xyz_unknown_interpreter
[testenv]
changedir=tests
- '''
- })
+ """,
+ },
+ )
result = cmd()
assert result.ret
- assert any('ERROR: InterpreterNotFound: xyz_unknown_interpreter' == l for l in result.outlines)
+ assert any(
+ "ERROR: InterpreterNotFound: xyz_unknown_interpreter" == l for l in result.outlines
+ ), result.outlines
result = cmd("-exyz")
assert result.ret
@@ -250,65 +281,81 @@ def test_unknown_interpreter_and_env(cmd, initproj):
def test_unknown_interpreter(cmd, initproj):
- initproj("interp123-0.5", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
+ initproj(
+ "interp123-0.5",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
[testenv:python]
basepython=xyz_unknown_interpreter
[testenv]
changedir=tests
- '''
- })
+ """,
+ },
+ )
result = cmd()
assert result.ret
- assert any('ERROR: InterpreterNotFound: xyz_unknown_interpreter' == l for l in result.outlines)
+ assert any(
+ "ERROR: InterpreterNotFound: xyz_unknown_interpreter" == l for l in result.outlines
+ ), result.outlines
def test_skip_platform_mismatch(cmd, initproj):
- initproj("interp123-0.5", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
+ initproj(
+ "interp123-0.5",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
[testenv]
changedir=tests
platform=x123
- '''
- })
+ """,
+ },
+ )
result = cmd()
assert not result.ret
- assert any('SKIPPED: python: platform mismatch' == l for l in result.outlines)
+ assert any(
+ "SKIPPED: python: platform mismatch" == l for l in result.outlines
+ ), result.outlines
def test_skip_unknown_interpreter(cmd, initproj):
- initproj("interp123-0.5", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
+ initproj(
+ "interp123-0.5",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
[testenv:python]
basepython=xyz_unknown_interpreter
[testenv]
changedir=tests
- '''
- })
+ """,
+ },
+ )
result = cmd("--skip-missing-interpreters")
assert not result.ret
- msg = 'SKIPPED: python: InterpreterNotFound: xyz_unknown_interpreter'
- assert any(msg == l for l in result.outlines)
+ msg = "SKIPPED: python: InterpreterNotFound: xyz_unknown_interpreter"
+ assert any(msg == l for l in result.outlines), result.outlines
def test_skip_unknown_interpreter_result_json(cmd, initproj, tmpdir):
report_path = tmpdir.join("toxresult.json")
- initproj("interp123-0.5", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
+ initproj(
+ "interp123-0.5",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
[testenv:python]
basepython=xyz_unknown_interpreter
[testenv]
changedir=tests
- '''
- })
+ """,
+ },
+ )
result = cmd("--skip-missing-interpreters", "--result-json", report_path)
assert not result.ret
- msg = 'SKIPPED: python: InterpreterNotFound: xyz_unknown_interpreter'
- assert any(msg == l for l in result.outlines)
+ msg = "SKIPPED: python: InterpreterNotFound: xyz_unknown_interpreter"
+ assert any(msg == l for l in result.outlines), result.outlines
setup_result_from_json = json.load(report_path)["testenvs"]["python"]["setup"]
for setup_step in setup_result_from_json:
assert "InterpreterNotFound" in setup_step["output"]
@@ -316,132 +363,158 @@ def test_skip_unknown_interpreter_result_json(cmd, initproj, tmpdir):
def test_unknown_dep(cmd, initproj):
- initproj("dep123-0.7", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
+ initproj(
+ "dep123-0.7",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
[testenv]
deps=qweqwe123
changedir=tests
- '''
- })
+ """,
+ },
+ )
result = cmd()
assert result.ret
- assert result.outlines[-1].startswith('ERROR: python: could not install deps [qweqwe123];')
+ assert result.outlines[-1].startswith("ERROR: python: could not install deps [qweqwe123];")
def test_venv_special_chars_issue252(cmd, initproj):
- initproj("pkg123-0.7", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'tox.ini': '''
+ initproj(
+ "pkg123-0.7",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "tox.ini": """
[tox]
envlist = special&&1
[testenv:special&&1]
changedir=tests
- '''
- })
+ """,
+ },
+ )
result = cmd()
assert result.ret == 0
- pattern = re.compile('special&&1 installed: .*pkg123==0.7.*')
- assert any(pattern.match(line) for line in result.outlines)
+ pattern = re.compile("special&&1 installed: .*pkg123==0.7.*")
+ assert any(pattern.match(line) for line in result.outlines), result.outlines
def test_unknown_environment(cmd, initproj):
- initproj("env123-0.7", filedefs={
- 'tox.ini': ''
- })
+ initproj("env123-0.7", filedefs={"tox.ini": ""})
result = cmd("-e", "qpwoei")
assert result.ret
assert result.out == "ERROR: unknown environment 'qpwoei'\n"
def test_skip_sdist(cmd, initproj):
- initproj("pkg123-0.7", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'setup.py': """
+ initproj(
+ "pkg123-0.7",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "setup.py": """
syntax error
""",
- 'tox.ini': '''
+ "tox.ini": """
[tox]
skipsdist=True
[testenv]
commands=python -c "print('done')"
- '''
- })
+ """,
+ },
+ )
result = cmd()
assert result.ret == 0
def test_minimal_setup_py_empty(cmd, initproj):
- initproj("pkg123-0.7", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'setup.py': """
+ initproj(
+ "pkg123-0.7",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "setup.py": """
""",
- 'tox.ini': ''
- })
+ "tox.ini": "",
+ },
+ )
result = cmd()
assert result.ret == 1
- assert result.outlines[-1] == 'ERROR: setup.py is empty'
+ assert result.outlines[-1] == "ERROR: setup.py is empty"
def test_minimal_setup_py_comment_only(cmd, initproj):
- initproj("pkg123-0.7", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'setup.py': """\n# some comment
+ initproj(
+ "pkg123-0.7",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "setup.py": """\n# some comment
""",
- 'tox.ini': ''
-
- })
+ "tox.ini": "",
+ },
+ )
result = cmd()
assert result.ret == 1
- assert result.outlines[-1] == 'ERROR: setup.py is empty'
+ assert result.outlines[-1] == "ERROR: setup.py is empty"
def test_minimal_setup_py_non_functional(cmd, initproj):
- initproj("pkg123-0.7", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'setup.py': """
+ initproj(
+ "pkg123-0.7",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "setup.py": """
import sys
""",
- 'tox.ini': ''
-
- })
+ "tox.ini": "",
+ },
+ )
result = cmd()
assert result.ret == 1
- assert any(re.match(r'.*ERROR.*check setup.py.*', l) for l in result.outlines)
+ assert any(re.match(r".*ERROR.*check setup.py.*", l) for l in result.outlines), result.outlines
def test_sdist_fails(cmd, initproj):
- initproj("pkg123-0.7", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'setup.py': """
+ initproj(
+ "pkg123-0.7",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "setup.py": """
syntax error
""",
- 'tox.ini': '',
- })
+ "tox.ini": "",
+ },
+ )
result = cmd()
assert result.ret
- assert any(re.match(r'.*FAIL.*could not package project.*', l) for l in result.outlines)
+ assert any(
+ re.match(r".*FAIL.*could not package project.*", l) for l in result.outlines
+ ), result.outlines
def test_no_setup_py_exits(cmd, initproj):
- initproj("pkg123-0.7", filedefs={
- 'tox.ini': """
+ initproj(
+ "pkg123-0.7",
+ filedefs={
+ "tox.ini": """
[testenv]
commands=python -c "2 + 2"
"""
- })
+ },
+ )
os.remove("setup.py")
result = cmd()
assert result.ret
- assert any(re.match(r'.*ERROR.*No setup.py file found.*', l) for l in result.outlines)
+ assert any(
+ re.match(r".*ERROR.*No setup.py file found.*", l) for l in result.outlines
+ ), result.outlines
def test_package_install_fails(cmd, initproj):
- initproj("pkg123-0.7", filedefs={
- 'tests': {'test_hello.py': "def test_hello(): pass"},
- 'setup.py': """
+ initproj(
+ "pkg123-0.7",
+ filedefs={
+ "tests": {"test_hello.py": "def test_hello(): pass"},
+ "setup.py": """
from setuptools import setup
setup(
name='pkg123',
@@ -453,42 +526,49 @@ def test_package_install_fails(cmd, initproj):
install_requires=['qweqwe123'],
)
""",
- 'tox.ini': '',
- })
+ "tox.ini": "",
+ },
+ )
result = cmd()
assert result.ret
- assert result.outlines[-1].startswith('ERROR: python: InvocationError for command ')
+ assert result.outlines[-1].startswith("ERROR: python: InvocationError for command ")
@pytest.fixture
def example123(initproj):
- yield initproj("example123-0.5", filedefs={
- 'tests': {
- 'test_hello.py': """
+ yield initproj(
+ "example123-0.5",
+ filedefs={
+ "tests": {
+ "test_hello.py": """
def test_hello(pytestconfig):
pass
- """,
- },
- 'tox.ini': '''
+ """
+ },
+ "tox.ini": """
[testenv]
changedir=tests
commands= pytest --basetemp={envtmpdir} \
--junitxml=junit-{envname}.xml
deps=pytest
- '''
- })
+ """,
+ },
+ )
def test_toxuone_env(cmd, example123):
result = cmd()
assert not result.ret
- assert re.match(r'.*generated\W+xml\W+file.*junit-python\.xml'
- r'.*\W+1\W+passed.*', result.out, re.DOTALL)
- result = cmd("-epython", )
+ assert re.match(
+ r".*generated\W+xml\W+file.*junit-python\.xml" r".*\W+1\W+passed.*", result.out, re.DOTALL
+ )
+ result = cmd("-epython")
assert not result.ret
- assert re.match(r'.*\W+1\W+passed.*'
- r'summary.*'
- r'python:\W+commands\W+succeeded.*', result.out, re.DOTALL)
+ assert re.match(
+ r".*\W+1\W+passed.*" r"summary.*" r"python:\W+commands\W+succeeded.*",
+ result.out,
+ re.DOTALL,
+ )
def test_different_config_cwd(cmd, example123, monkeypatch):
@@ -496,9 +576,11 @@ def test_different_config_cwd(cmd, example123, monkeypatch):
monkeypatch.chdir(example123.dirname)
result = cmd("-c", "example123/tox.ini")
assert not result.ret
- assert re.match(r'.*\W+1\W+passed.*'
- r'summary.*'
- r'python:\W+commands\W+succeeded.*', result.out, re.DOTALL)
+ assert re.match(
+ r".*\W+1\W+passed.*" r"summary.*" r"python:\W+commands\W+succeeded.*",
+ result.out,
+ re.DOTALL,
+ )
def test_json(cmd, example123):
@@ -511,36 +593,51 @@ def test_json(cmd, example123):
assert result.ret == 1
data = json.load(jsonpath.open("r"))
verify_json_report_format(data)
- assert re.match(r'.*\W+1\W+failed.*'
- r'summary.*'
- r'python:\W+commands\W+failed.*', result.out, re.DOTALL)
+ assert re.match(
+ r".*\W+1\W+failed.*" r"summary.*" r"python:\W+commands\W+failed.*", result.out, re.DOTALL
+ )
def test_developz(initproj, cmd):
- initproj("example123", filedefs={'tox.ini': """
- """})
+ initproj(
+ "example123",
+ filedefs={
+ "tox.ini": """
+ """
+ },
+ )
result = cmd("-vv", "--develop")
assert not result.ret
assert "sdist-make" not in result.out
def test_usedevelop(initproj, cmd):
- initproj("example123", filedefs={'tox.ini': """
+ initproj(
+ "example123",
+ filedefs={
+ "tox.ini": """
[testenv]
usedevelop=True
- """})
+ """
+ },
+ )
result = cmd("-vv")
assert not result.ret
assert "sdist-make" not in result.out
def test_usedevelop_mixed(initproj, cmd):
- initproj("example123", filedefs={'tox.ini': """
+ initproj(
+ "example123",
+ filedefs={
+ "tox.ini": """
[testenv:devenv]
usedevelop=True
[testenv:nondev]
usedevelop=False
- """})
+ """
+ },
+ )
# running only 'devenv' should not do sdist
result = cmd("-vv", "-e", "devenv")
@@ -555,42 +652,51 @@ def test_usedevelop_mixed(initproj, cmd):
@pytest.mark.parametrize("src_root", [".", "src"])
def test_test_usedevelop(cmd, initproj, src_root, monkeypatch):
- base = initproj("example123-0.5", src_root=src_root, filedefs={
- 'tests': {
- 'test_hello.py': """
+ base = initproj(
+ "example123-0.5",
+ src_root=src_root,
+ filedefs={
+ "tests": {
+ "test_hello.py": """
def test_hello(pytestconfig):
pass
- """,
- },
- 'tox.ini': '''
+ """
+ },
+ "tox.ini": """
[testenv]
usedevelop=True
changedir=tests
commands=
pytest --basetemp={envtmpdir} --junitxml=junit-{envname}.xml []
deps=pytest
- '''
- })
+ """,
+ },
+ )
result = cmd("-v")
assert not result.ret
- assert re.match(r'.*generated\W+xml\W+file.*junit-python\.xml'
- r'.*\W+1\W+passed.*', result.out, re.DOTALL)
+ assert re.match(
+ r".*generated\W+xml\W+file.*junit-python\.xml" r".*\W+1\W+passed.*", result.out, re.DOTALL
+ )
assert "sdist-make" not in result.out
- result = cmd("-epython", )
+ result = cmd("-epython")
assert not result.ret
assert "develop-inst-noop" in result.out
- assert re.match(r'.*\W+1\W+passed.*'
- r'summary.*'
- r'python:\W+commands\W+succeeded.*', result.out, re.DOTALL)
+ assert re.match(
+ r".*\W+1\W+passed.*" r"summary.*" r"python:\W+commands\W+succeeded.*",
+ result.out,
+ re.DOTALL,
+ )
# see that things work with a different CWD
monkeypatch.chdir(base.dirname)
result = cmd("-c", "example123/tox.ini")
assert not result.ret
assert "develop-inst-noop" in result.out
- assert re.match(r'.*\W+1\W+passed.*'
- r'summary.*'
- r'python:\W+commands\W+succeeded.*', result.out, re.DOTALL)
+ assert re.match(
+ r".*\W+1\W+passed.*" r"summary.*" r"python:\W+commands\W+succeeded.*",
+ result.out,
+ re.DOTALL,
+ )
monkeypatch.chdir(base)
# see that tests can also fail and retcode is correct
@@ -600,13 +706,13 @@ def test_test_usedevelop(cmd, initproj, src_root, monkeypatch):
result = cmd()
assert result.ret
assert "develop-inst-noop" in result.out
- assert re.match(r'.*\W+1\W+failed.*'
- r'summary.*'
- r'python:\W+commands\W+failed.*', result.out, re.DOTALL)
+ assert re.match(
+ r".*\W+1\W+failed.*" r"summary.*" r"python:\W+commands\W+failed.*", result.out, re.DOTALL
+ )
# test develop is called if setup.py changes
setup_py = py.path.local("setup.py")
- setup_py.write(setup_py.read() + ' ')
+ setup_py.write(setup_py.read() + " ")
result = cmd()
assert result.ret
assert "develop-inst-nodeps" in result.out
@@ -615,61 +721,83 @@ def test_test_usedevelop(cmd, initproj, src_root, monkeypatch):
def _alwayscopy_not_supported():
# This is due to virtualenv bugs with alwayscopy in some platforms
# see: https://github.com/pypa/virtualenv/issues/565
- if hasattr(platform, 'linux_distribution'):
+ if hasattr(platform, "linux_distribution"):
_dist = platform.linux_distribution(full_distribution_name=False)
(name, version, arch) = _dist
- if any((name == 'centos' and version[0] == '7',
- name == 'SuSE' and arch == 'x86_64')):
+ if any((name == "centos" and version[0] == "7", name == "SuSE" and arch == "x86_64")):
return True
return False
@pytest.mark.skipif(_alwayscopy_not_supported(), reason="Platform doesnt support alwayscopy")
def test_alwayscopy(initproj, cmd):
- initproj("example123", filedefs={'tox.ini': """
+ initproj(
+ "example123",
+ filedefs={
+ "tox.ini": """
[testenv]
commands={envpython} --version
alwayscopy=True
- """})
+ """
+ },
+ )
result = cmd("-vv")
assert not result.ret
assert "virtualenv --always-copy" in result.out
def test_alwayscopy_default(initproj, cmd):
- initproj("example123", filedefs={'tox.ini': """
+ initproj(
+ "example123",
+ filedefs={
+ "tox.ini": """
[testenv]
commands={envpython} --version
- """})
+ """
+ },
+ )
result = cmd("-vv")
assert not result.ret
assert "virtualenv --always-copy" not in result.out
def test_empty_activity_ignored(initproj, cmd):
- initproj("example123", filedefs={'tox.ini': """
+ initproj(
+ "example123",
+ filedefs={
+ "tox.ini": """
[testenv]
list_dependencies_command=echo
commands={envpython} --version
- """})
+ """
+ },
+ )
result = cmd()
assert not result.ret
assert "installed:" not in result.out
def test_empty_activity_shown_verbose(initproj, cmd):
- initproj("example123", filedefs={'tox.ini': """
+ initproj(
+ "example123",
+ filedefs={
+ "tox.ini": """
[testenv]
list_dependencies_command=echo
commands={envpython} --version
- """})
+ """
+ },
+ )
result = cmd("-v")
assert not result.ret
assert "installed:" in result.out
def test_test_piphelp(initproj, cmd):
- initproj("example123", filedefs={'tox.ini': """
+ initproj(
+ "example123",
+ filedefs={
+ "tox.ini": """
# content of: tox.ini
[testenv]
commands=pip -h
@@ -677,76 +805,97 @@ def test_test_piphelp(initproj, cmd):
basepython=python
[testenv:py36]
basepython=python
- """})
+ """
+ },
+ )
result = cmd()
assert not result.ret
def test_notest(initproj, cmd):
- initproj("example123", filedefs={'tox.ini': """
+ initproj(
+ "example123",
+ filedefs={
+ "tox.ini": """
# content of: tox.ini
[testenv:py26]
basepython=python
- """})
+ """
+ },
+ )
result = cmd("-v", "--notest")
assert not result.ret
- assert re.match(r'.*summary.*'
- r'py26\W+skipped\W+tests.*', result.out, re.DOTALL)
+ assert re.match(r".*summary.*" r"py26\W+skipped\W+tests.*", result.out, re.DOTALL)
result = cmd("-v", "--notest", "-epy26")
assert not result.ret
- assert re.match(r'.*py26\W+reusing.*', result.out, re.DOTALL)
+ assert re.match(r".*py26\W+reusing.*", result.out, re.DOTALL)
def test_PYC(initproj, cmd, monkeypatch):
- initproj("example123", filedefs={'tox.ini': ''})
+ initproj("example123", filedefs={"tox.ini": ""})
monkeypatch.setenv("PYTHONDOWNWRITEBYTECODE", 1)
result = cmd("-v", "--notest")
assert not result.ret
- assert 'create' in result.out
+ assert "create" in result.out
def test_env_VIRTUALENV_PYTHON(initproj, cmd, monkeypatch):
- initproj("example123", filedefs={'tox.ini': ''})
- monkeypatch.setenv("VIRTUALENV_PYTHON", '/FOO')
+ initproj("example123", filedefs={"tox.ini": ""})
+ monkeypatch.setenv("VIRTUALENV_PYTHON", "/FOO")
result = cmd("-v", "--notest")
assert not result.ret, result.outlines
- assert 'create' in result.out
+ assert "create" in result.out
def test_sdistonly(initproj, cmd):
- initproj("example123", filedefs={'tox.ini': """
- """})
+ initproj(
+ "example123",
+ filedefs={
+ "tox.ini": """
+ """
+ },
+ )
result = cmd("-v", "--sdistonly")
assert not result.ret
- assert re.match(r'.*sdist-make.*setup.py.*', result.out, re.DOTALL)
+ assert re.match(r".*sdist-make.*setup.py.*", result.out, re.DOTALL)
assert "-mvirtualenv" not in result.out
def test_separate_sdist_no_sdistfile(cmd, initproj, tmpdir):
distshare = tmpdir.join("distshare")
- initproj(("pkg123-foo", "0.7"), filedefs={
- 'tox.ini': """
+ initproj(
+ ("pkg123-foo", "0.7"),
+ filedefs={
+ "tox.ini": """
[tox]
distshare={}
- """.format(distshare)
- })
+ """.format(
+ distshare
+ )
+ },
+ )
result = cmd("--sdistonly")
assert not result.ret
distshare_files = distshare.listdir()
assert len(distshare_files) == 1
sdistfile = distshare_files[0]
- assert 'pkg123-foo-0.7.zip' in str(sdistfile)
+ assert "pkg123-foo-0.7.zip" in str(sdistfile)
def test_separate_sdist(cmd, initproj, tmpdir):
distshare = tmpdir.join("distshare")
- initproj("pkg123-0.7", filedefs={
- 'tox.ini': """
+ initproj(
+ "pkg123-0.7",
+ filedefs={
+ "tox.ini": """
[tox]
- distshare=%s
- sdistsrc={distshare}/pkg123-0.7.zip
- """ % distshare
- })
+ distshare={}
+ sdistsrc={{distshare}}/pkg123-0.7.zip
+ """.format(
+ distshare
+ )
+ },
+ )
result = cmd("--sdistonly")
assert not result.ret
sdistfiles = distshare.listdir()
@@ -759,11 +908,16 @@ def test_separate_sdist(cmd, initproj, tmpdir):
def test_sdist_latest(tmpdir, newconfig):
distshare = tmpdir.join("distshare")
- config = newconfig([], """
+ config = newconfig(
+ [],
+ """
[tox]
- distshare=%s
- sdistsrc={distshare}/pkg123-*
- """ % distshare)
+ distshare={}
+ sdistsrc={{distshare}}/pkg123-*
+ """.format(
+ distshare
+ ),
+ )
p = distshare.ensure("pkg123-1.4.5.zip")
distshare.ensure("pkg123-1.4.5a1.zip")
session = Session(config)
@@ -773,51 +927,63 @@ def test_sdist_latest(tmpdir, newconfig):
def test_installpkg(tmpdir, newconfig):
p = tmpdir.ensure("pkg123-1.0.zip")
- config = newconfig(["--installpkg=%s" % p], "")
+ config = newconfig(["--installpkg={}".format(p)], "")
session = Session(config)
sdist_path = session.get_installpkg_path()
assert sdist_path == p
def test_envsitepackagesdir(cmd, initproj):
- initproj("pkg512-0.0.5", filedefs={
- 'tox.ini': """
+ initproj(
+ "pkg512-0.0.5",
+ filedefs={
+ "tox.ini": """
[testenv]
commands=
python -c "print(r'X:{envsitepackagesdir}')"
- """})
+ """
+ },
+ )
result = cmd()
assert result.ret == 0
- assert re.match(r'.*\nX:.*tox.*site-packages.*', result.out, re.DOTALL)
+ assert re.match(r".*\nX:.*tox.*site-packages.*", result.out, re.DOTALL)
def test_envsitepackagesdir_skip_missing_issue280(cmd, initproj):
- initproj("pkg513-0.0.5", filedefs={
- 'tox.ini': """
+ initproj(
+ "pkg513-0.0.5",
+ filedefs={
+ "tox.ini": """
[testenv]
basepython=/usr/bin/qwelkjqwle
commands=
{envsitepackagesdir}
- """})
+ """
+ },
+ )
result = cmd("--skip-missing-interpreters")
assert result.ret == 0
- assert re.match(r'.*SKIPPED:.*qwelkj.*', result.out, re.DOTALL)
+ assert re.match(r".*SKIPPED:.*qwelkj.*", result.out, re.DOTALL)
-@pytest.mark.parametrize('verbosity', ['', '-v', '-vv'])
+@pytest.mark.parametrize("verbosity", ["", "-v", "-vv"])
def test_verbosity(cmd, initproj, verbosity):
- initproj("pkgX-0.0.5", filedefs={
- 'tox.ini': """
+ initproj(
+ "pkgX-0.0.5",
+ filedefs={
+ "tox.ini": """
[testenv]
- """})
+ """
+ },
+ )
result = cmd(verbosity)
assert result.ret == 0
needle = "Successfully installed pkgX-0.0.5"
- if verbosity == '-vv':
- assert any(needle in line for line in result.outlines)
+ if verbosity == "-vv":
+ assert any(needle in line for line in result.outlines), result.outlines
else:
- assert all(needle not in line for line in result.outlines)
+ assert all(needle not in line for line in result.outlines), result.outlines
def verify_json_report_format(data, testenvs=True):
@@ -840,24 +1006,27 @@ def verify_json_report_format(data, testenvs=True):
def test_envtmpdir(initproj, cmd):
- initproj("foo", filedefs={
- # This file first checks that envtmpdir is existent and empty. Then it
- # creates an empty file in that directory. The tox command is run
- # twice below, so this is to test whether the directory is cleared
- # before the second run.
- 'check_empty_envtmpdir.py': '''if True:
+ initproj(
+ "foo",
+ filedefs={
+ # This file first checks that envtmpdir is existent and empty. Then it
+ # creates an empty file in that directory. The tox command is run
+ # twice below, so this is to test whether the directory is cleared
+ # before the second run.
+ "check_empty_envtmpdir.py": """if True:
import os
from sys import argv
envtmpdir = argv[1]
assert os.path.exists(envtmpdir)
assert os.listdir(envtmpdir) == []
open(os.path.join(envtmpdir, 'test'), 'w').close()
- ''',
- 'tox.ini': '''
+ """,
+ "tox.ini": """
[testenv]
commands=python check_empty_envtmpdir.py {envtmpdir}
- '''
- })
+ """,
+ },
+ )
result = cmd()
assert not result.ret
@@ -867,42 +1036,47 @@ def test_envtmpdir(initproj, cmd):
def test_missing_env_fails(initproj, cmd):
- initproj("foo", filedefs={'tox.ini': "[testenv:foo]\ncommands={env:VAR}"})
+ initproj("foo", filedefs={"tox.ini": "[testenv:foo]\ncommands={env:VAR}"})
result = cmd()
assert result.ret == 1
- assert result.out.endswith("foo: unresolvable substitution(s): 'VAR'."
- " Environment variables are missing or defined recursively.\n")
+ assert result.out.endswith(
+ "foo: unresolvable substitution(s): 'VAR'."
+ " Environment variables are missing or defined recursively.\n"
+ )
def test_tox_console_script():
- result = subprocess.check_call(['tox', '--help'])
+ result = subprocess.check_call(["tox", "--help"])
assert result == 0
def test_tox_quickstart_script():
- result = subprocess.check_call(['tox-quickstart', '--help'])
+ result = subprocess.check_call(["tox-quickstart", "--help"])
assert result == 0
def test_tox_cmdline_no_args(monkeypatch):
- monkeypatch.setattr(sys, 'argv', ['caller_script', '--help'])
+ monkeypatch.setattr(sys, "argv", ["caller_script", "--help"])
with pytest.raises(SystemExit):
tox.cmdline()
def test_tox_cmdline_args():
with pytest.raises(SystemExit):
- tox.cmdline(['caller_script', '--help'])
+ tox.cmdline(["caller_script", "--help"])
-@pytest.mark.parametrize('exit_code', [0, 6])
+@pytest.mark.parametrize("exit_code", [0, 6])
def test_exit_code(initproj, cmd, exit_code, mocker):
""" Check for correct InvocationError, with exit code,
except for zero exit code """
import tox.exception
- mocker.spy(tox.exception, 'exit_code_str')
- tox_ini_content = "[testenv:foo]\ncommands=python -c 'import sys; sys.exit(%d)'" % exit_code
- initproj("foo", filedefs={'tox.ini': tox_ini_content})
+
+ mocker.spy(tox.exception, "exit_code_str")
+ tox_ini_content = "[testenv:foo]\ncommands=python -c 'import sys; sys.exit({:d})'".format(
+ exit_code
+ )
+ initproj("foo", filedefs={"tox.ini": tox_ini_content})
cmd()
if exit_code:
# need mocker.spy above
@@ -910,10 +1084,10 @@ def test_exit_code(initproj, cmd, exit_code, mocker):
(args, kwargs) = tox.exception.exit_code_str.call_args
assert kwargs == {}
(call_error_name, call_command, call_exit_code) = args
- assert call_error_name == 'InvocationError'
+ assert call_error_name == "InvocationError"
# quotes are removed in result.out
# do not include "python" as it is changed to python.EXE by appveyor
- expected_command_arg = ' -c import sys; sys.exit(%d)' % exit_code
+ expected_command_arg = " -c import sys; sys.exit({:d})".format(exit_code)
assert expected_command_arg in call_command
assert call_exit_code == exit_code
else:
diff --git a/tox.ini b/tox.ini
index da2b2106..786fb251 100644
--- a/tox.ini
+++ b/tox.ini
@@ -35,9 +35,9 @@ passenv = {[testenv]passenv}
PROGRAMDATA
extras = lint
description = run static analysis and style check using flake8
-commands = python -m flake8 --show-source tox setup.py {posargs}
+commands = pre-commit run --all-files --show-diff-on-failure
+ python -m flake8 --show-source tox setup.py {posargs}
python -m flake8 --show-source doc tests {posargs}
- pre-commit run --all-files --show-diff-on-failure
python -c 'print("hint: run {envdir}/bin/pre-commit install to add checks as pre-commit hook")'
diff --git a/tox/__init__.py b/tox/__init__.py
index c7560c82..81d7f688 100644
--- a/tox/__init__.py
+++ b/tox/__init__.py
@@ -6,35 +6,33 @@ If objects are marked experimental they might change between minor versions.
To override/modify tox behaviour via plugins see `tox.hookspec` and its use with pluggy.
"""
-from pkg_resources import DistributionNotFound, get_distribution
-
import pluggy
+from pkg_resources import DistributionNotFound, get_distribution
from . import exception
from .constants import INFO, PIP, PYTHON
from .hookspecs import hookspec
__all__ = (
- '__version__', # tox version
- 'cmdline', # run tox as part of another program/IDE (same behaviour as called standalone)
- 'hookimpl', # Hook implementation marker to be imported by plugins
- 'exception', # tox specific exceptions
-
+ "__version__", # tox version
+ "cmdline", # run tox as part of another program/IDE (same behaviour as called standalone)
+ "hookimpl", # Hook implementation marker to be imported by plugins
+ "exception", # tox specific exceptions
# EXPERIMENTAL CONSTANTS API
- 'PYTHON', 'INFO', 'PIP',
-
+ "PYTHON",
+ "INFO",
+ "PIP",
# DEPRECATED - will be removed from API in tox 4
- 'hookspec',
+ "hookspec",
)
hookimpl = pluggy.HookimplMarker("tox")
try:
_full_version = get_distribution(__name__).version
- __version__ = _full_version.split('+', 1)[0]
+ __version__ = _full_version.split("+", 1)[0]
except DistributionNotFound:
- __version__ = '0.0.0.dev0'
-
+ __version__ = "0.0.0.dev0"
# NOTE: must come last due to circular import
from .session import cmdline # noqa
diff --git a/tox/__main__.py b/tox/__main__.py
index 7d3c3cc1..821fa480 100644
--- a/tox/__main__.py
+++ b/tox/__main__.py
@@ -1,4 +1,4 @@
import tox
-if __name__ == '__main__':
+if __name__ == "__main__":
tox.cmdline()
diff --git a/tox/_pytestplugin.py b/tox/_pytestplugin.py
index 71d1f45a..5f5133bc 100644
--- a/tox/_pytestplugin.py
+++ b/tox/_pytestplugin.py
@@ -15,24 +15,28 @@ from tox.result import ResultLog
from tox.session import Session, main
from tox.venv import VirtualEnv
-mark_dont_run_on_windows = pytest.mark.skipif(os.name == 'nt', reason="non windows test")
-mark_dont_run_on_posix = pytest.mark.skipif(os.name == 'posix', reason="non posix test")
+mark_dont_run_on_windows = pytest.mark.skipif(os.name == "nt", reason="non windows test")
+mark_dont_run_on_posix = pytest.mark.skipif(os.name == "posix", reason="non posix test")
def pytest_configure():
- if 'TOXENV' in os.environ:
- del os.environ['TOXENV']
- if 'HUDSON_URL' in os.environ:
- del os.environ['HUDSON_URL']
+ if "TOXENV" in os.environ:
+ del os.environ["TOXENV"]
+ if "HUDSON_URL" in os.environ:
+ del os.environ["HUDSON_URL"]
def pytest_addoption(parser):
- parser.addoption("--no-network", action="store_true", dest="no_network",
- help="don't run tests requiring network")
+ parser.addoption(
+ "--no-network",
+ action="store_true",
+ dest="no_network",
+ help="don't run tests requiring network",
+ )
def pytest_report_header():
- return "tox comes from: {}".format(repr(tox.__file__))
+ return "tox comes from: {!r}".format(tox.__file__)
@pytest.fixture
@@ -43,6 +47,7 @@ def work_in_clean_dir(tmpdir):
@pytest.fixture(name="newconfig")
def create_new_config_file(tmpdir):
+
def create_new_config_file_(args, source=None, plugins=()):
if source is None:
source = args
@@ -52,6 +57,7 @@ def create_new_config_file(tmpdir):
p.write(s)
with tmpdir.as_cwd():
return parseconfig(args, plugins=plugins)
+
return create_new_config_file_
@@ -62,7 +68,7 @@ def cmd(request, capfd, monkeypatch):
request.addfinalizer(py.path.local().chdir)
def run(*argv):
- key = str(b'PYTHONPATH')
+ key = str(b"PYTHONPATH")
python_paths = (i for i in (str(os.getcwd()), os.getenv(key)) if i)
monkeypatch.setenv(key, os.pathsep.join(python_paths))
with RunResult(capfd, argv) as result:
@@ -74,10 +80,12 @@ def cmd(request, capfd, monkeypatch):
except OSError as e:
result.ret = e.errno
return result
+
yield run
class RunResult:
+
def __init__(self, capfd, args):
self._capfd = capfd
self.args = args
@@ -101,11 +109,13 @@ class RunResult:
return self.out.splitlines()
def __repr__(self):
- return 'RunResult(ret={}, args={}, out=\n{}\n, err=\n{})'.format(
- self.ret, ' '.join(str(i) for i in self.args), self.out, self.err)
+ return "RunResult(ret={}, args={}, out=\n{}\n, err=\n{})".format(
+ self.ret, " ".join(str(i) for i in self.args), self.out, self.err
+ )
class ReportExpectMock:
+
def __init__(self, session):
self._calls = []
self._index = -1
@@ -117,13 +127,13 @@ class ReportExpectMock:
def __getattr__(self, name):
if name[0] == "_":
raise AttributeError(name)
- elif name == 'verbosity':
+ elif name == "verbosity":
# FIXME: special case for property on Reporter class, may it be generalized?
return 0
def generic_report(*args, **_):
self._calls.append((name,) + args)
- print("%s" % (self._calls[-1],))
+ print("{}".format(self._calls[-1]))
return generic_report
@@ -138,8 +148,10 @@ class ReportExpectMock:
return call
newindex += 1
raise LookupError(
- "looking for %r, no reports found at >=%d in %r" %
- (cat, self._index + 1, self._calls))
+ "looking for {!r}, no reports found at >={:d} in {!r}".format(
+ cat, self._index + 1, self._calls
+ )
+ )
def expect(self, cat, messagepattern="*", invert=False):
__tracebackhide__ = True
@@ -154,19 +166,23 @@ class ReportExpectMock:
lmsg = str(lmsg).replace("\n", " ")
if fnmatch(lmsg, messagepattern):
if invert:
- raise AssertionError("found %s(%r), didn't expect it" %
- (cat, messagepattern))
+ raise AssertionError(
+ "found {}({!r}), didn't expect it".format(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 {}({!r}), no reports found at >={:d} in {!r}".format(
+ 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]
self.args = args[1:]
@@ -186,7 +202,9 @@ class pcallMock:
@pytest.fixture(name="mocksession")
def create_mocksession(request):
+
class MockSession(Session):
+
def __init__(self):
self._clearmocks()
self.config = request.getfixturevalue("newconfig")([], "")
@@ -208,14 +226,17 @@ def create_mocksession(request):
pm = pcallMock(args, cwd, env, stdout, stderr, shell)
self._pcalls.append(pm)
return pm
+
return MockSession()
@pytest.fixture
def newmocksession(mocksession, newconfig):
+
def newmocksession_(args, source, plugins=()):
mocksession.config = newconfig(args, source, plugins=plugins)
return mocksession
+
return newmocksession_
@@ -223,8 +244,7 @@ def getdecoded(out):
try:
return out.decode("utf-8")
except UnicodeDecodeError:
- return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % (
- py.io.saferepr(out),)
+ return "INTERNAL not-utf8-decodeable, truncated string:\n{}".format(py.io.saferepr(out))
@pytest.fixture
@@ -252,11 +272,12 @@ def initproj(tmpdir):
name.egg-info/ # created later on package build
setup.py
"""
+
def initproj_(nameversion, filedefs=None, src_root="."):
if filedefs is None:
filedefs = {}
if not src_root:
- src_root = '.'
+ src_root = "."
if isinstance(nameversion, six.string_types):
parts = nameversion.split(str("-"))
if len(parts) == 1:
@@ -266,32 +287,44 @@ def initproj(tmpdir):
name, version = nameversion
base = tmpdir.join(name)
src_root_path = _path_join(base, src_root)
- assert base == src_root_path or src_root_path.relto(base), (
- '`src_root` must be the constructed project folder or its direct '
- 'or indirect subfolder')
+ assert (
+ base == src_root_path or src_root_path.relto(base)
+ ), "`src_root` must be the constructed project folder or its direct or indirect subfolder"
+
base.ensure(dir=1)
create_files(base, filedefs)
- if not _filedefs_contains(base, filedefs, 'setup.py'):
- create_files(base, {'setup.py': """
+ if not _filedefs_contains(base, filedefs, "setup.py"):
+ create_files(
+ base,
+ {
+ "setup.py": """
from setuptools import setup, find_packages
setup(
- name='%(name)s',
- description='%(name)s project',
- version='%(version)s',
+ name='{name}',
+ description='{name} project',
+ version='{version}',
license='MIT',
platforms=['unix', 'win32'],
- packages=find_packages('%(src_root)s'),
- package_dir={'':'%(src_root)s'},
+ packages=find_packages('{src_root}'),
+ package_dir={{'':'{src_root}'}},
)
- """ % locals()})
+ """.format(
+ **locals()
+ )
+ },
+ )
if not _filedefs_contains(base, filedefs, src_root_path.join(name)):
- create_files(src_root_path, {name: {'__init__.py': '__version__ = %r' % version}})
- manifestlines = ["include %s" % p.relto(base)
- for p in base.visit(lambda x: x.check(file=1))]
+ create_files(
+ src_root_path, {name: {"__init__.py": "__version__ = {!r}".format(version)}}
+ )
+ manifestlines = [
+ "include {}".format(p.relto(base)) for p in base.visit(lambda x: x.check(file=1))
+ ]
create_files(base, {"MANIFEST.in": "\n".join(manifestlines)})
- print("created project in %s" % base)
+ print("created project in {}".format(base))
base.chdir()
return base
+
return initproj_
diff --git a/tox/_quickstart.py b/tox/_quickstart.py
index 01269677..bb6c229c 100644
--- a/tox/_quickstart.py
+++ b/tox/_quickstart.py
@@ -43,13 +43,14 @@ import argparse
import codecs
import os
import sys
+import textwrap
import six
import tox
-ALTERNATIVE_CONFIG_NAME = 'tox-generated.ini'
-QUICKSTART_CONF = '''\
+ALTERNATIVE_CONFIG_NAME = "tox-generated.ini"
+QUICKSTART_CONF = """\
# tox (https://tox.readthedocs.io/) is a tool for running tests
# in multiple virtualenvs. This configuration file will run the
# test suite on all supported python versions. To use it, "pip install tox"
@@ -63,7 +64,7 @@ deps =
{deps}
commands =
{commands}
-'''
+"""
class ValidationError(Exception):
@@ -77,24 +78,24 @@ def nonempty(x):
def choice(*l):
+
def val(x):
if x not in l:
- raise ValidationError('Please enter one of %s.' % ', '.join(l))
+ raise ValidationError("Please enter one of {}.".format(", ".join(l)))
return x
return val
def boolean(x):
- if x.upper() not in ('Y', 'YES', 'N', 'NO'):
+ if x.upper() not in ("Y", "YES", "N", "NO"):
raise ValidationError("Please enter either 'y' or 'n'.")
- return x.upper() in ('Y', 'YES')
+ 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'.")
+ if not (x[0:1] == "." and len(x) > 1):
+ raise ValidationError("Please enter a file suffix, e.g. '.rst' or '.txt'.")
return x
@@ -109,36 +110,39 @@ def list_modificator(answer, existing=None):
existing = [existing]
if not answer:
return existing
- existing.extend([t.strip() for t in answer.split(',') if t.strip()])
+ existing.extend([t.strip() for t in answer.split(",") if t.strip()])
return existing
def do_prompt(map_, key, text, default=None, validator=nonempty, modificator=None):
while True:
- prompt = '> %s [%s]: ' % (text, default) if default else '> %s: ' % text
+ prompt = "> {} [{}]: ".format(text, default) if default else "> {}: ".format(text)
answer = six.moves.input(prompt)
if default and not answer:
answer = default
# FIXME use six instead of self baked solution
+ # noinspection PyUnresolvedReferences
if sys.version_info < (3,) and not isinstance(answer, unicode): # noqa
# for Python 2.x, try to get a Unicode string out of it
- if answer.decode('ascii', 'replace').encode('ascii', 'replace') != answer:
- term_encoding = getattr(sys.stdin, 'encoding', None)
+ if answer.decode("ascii", "replace").encode("ascii", "replace") != answer:
+ term_encoding = getattr(sys.stdin, "encoding", None)
if term_encoding:
answer = answer.decode(term_encoding)
else:
- print('* Note: non-ASCII characters entered but terminal encoding unknown '
- '-> assuming UTF-8 or Latin-1.')
+ print(
+ "* Note: non-ASCII characters entered but terminal encoding unknown"
+ " -> assuming UTF-8 or Latin-1."
+ )
try:
- answer = answer.decode('utf-8')
+ answer = answer.decode("utf-8")
except UnicodeDecodeError:
- answer = answer.decode('latin1')
+ answer = answer.decode("latin1")
if validator:
try:
answer = validator(answer)
except ValidationError:
err = sys.exc_info()[1]
- print('* ' + str(err))
+ print("* " + str(err))
continue
break
map_[key] = modificator(answer, map_.get(key)) if modificator else answer
@@ -146,105 +150,144 @@ def do_prompt(map_, key, text, default=None, validator=nonempty, modificator=Non
def ask_user(map_):
"""modify *map_* in place by getting info from the user."""
- print('Welcome to the tox %s quickstart utility.' % tox.__version__)
- print('This utility will ask you a few questions and then generate a simple configuration '
- 'file to help get you started using tox.\n'
- 'Please enter values for the following settings (just press Enter to accept a '
- 'default value, if one is given in brackets).\n')
- print('What Python versions do you want to test against?\n'
- ' [1] %s\n'
- ' [2] py27, %s\n'
- ' [3] (All versions) %s\n'
- ' [4] Choose each one-by-one' % (
- tox.PYTHON.CURRENT_RELEASE_ENV, tox.PYTHON.CURRENT_RELEASE_ENV,
- ', '.join(tox.PYTHON.QUICKSTART_PY_ENVS)))
- do_prompt(map_, 'canned_pyenvs', 'Enter the number of your choice',
- default='3', validator=choice('1', '2', '3', '4'))
- if map_['canned_pyenvs'] == '1':
+ print("Welcome to the tox {} quickstart utility.".format(tox.__version__))
+ print(
+ "This utility will ask you a few questions and then generate a simple configuration "
+ "file to help get you started using tox.\n"
+ "Please enter values for the following settings (just press Enter to accept a "
+ "default value, if one is given in brackets).\n"
+ )
+ print(
+ textwrap.dedent(
+ """What Python versions do you want to test against?
+ [1] {}
+ [2] py27, {}
+ [3] (All versions) {}
+ [4] Choose each one-by-one"""
+ ).format(
+ tox.PYTHON.CURRENT_RELEASE_ENV,
+ tox.PYTHON.CURRENT_RELEASE_ENV,
+ ", ".join(tox.PYTHON.QUICKSTART_PY_ENVS),
+ )
+ )
+ do_prompt(
+ map_,
+ "canned_pyenvs",
+ "Enter the number of your choice",
+ default="3",
+ validator=choice("1", "2", "3", "4"),
+ )
+ if map_["canned_pyenvs"] == "1":
map_[tox.PYTHON.CURRENT_RELEASE_ENV] = True
- elif map_['canned_pyenvs'] == '2':
- for pyenv in ('py27', tox.PYTHON.CURRENT_RELEASE_ENV):
+ elif map_["canned_pyenvs"] == "2":
+ for pyenv in ("py27", tox.PYTHON.CURRENT_RELEASE_ENV):
map_[pyenv] = True
- elif map_['canned_pyenvs'] == '3':
+ elif map_["canned_pyenvs"] == "3":
for pyenv in tox.PYTHON.QUICKSTART_PY_ENVS:
map_[pyenv] = True
- elif map_['canned_pyenvs'] == '4':
+ elif map_["canned_pyenvs"] == "4":
for pyenv in tox.PYTHON.QUICKSTART_PY_ENVS:
if pyenv not in map_:
- do_prompt(map_, pyenv, 'Test your project with %s (Y/n)' % pyenv, 'Y',
- validator=boolean)
- print('What command should be used to test your project? Examples:\n'
- ' - pytest\n'
- ' - python -m unittest discover\n'
- ' - python setup.py test\n'
- ' - trial package.module\n')
- do_prompt(map_, 'commands', 'Type the command to run your tests',
- default='pytest', modificator=list_modificator)
- print('What extra dependencies do your tests have?')
- map_['deps'] = get_default_deps(map_['commands'])
- if map_['deps']:
- print("default dependencies are: %s" % map_['deps'])
- do_prompt(map_, 'deps', 'Comma-separated list of dependencies',
- validator=None, modificator=list_modificator)
+ do_prompt(
+ map_,
+ pyenv,
+ "Test your project with {} (Y/n)".format(pyenv),
+ "Y",
+ validator=boolean,
+ )
+ print(
+ textwrap.dedent(
+ """What command should be used to test your project? Examples:\
+ - pytest\n"
+ - python -m unittest discover
+ - python setup.py test
+ - trial package.module"""
+ )
+ )
+ do_prompt(
+ map_,
+ "commands",
+ "Type the command to run your tests",
+ default="pytest",
+ modificator=list_modificator,
+ )
+ print("What extra dependencies do your tests have?")
+ map_["deps"] = get_default_deps(map_["commands"])
+ if map_["deps"]:
+ print("default dependencies are: {}".format(map_["deps"]))
+ do_prompt(
+ map_,
+ "deps",
+ "Comma-separated list of dependencies",
+ validator=None,
+ modificator=list_modificator,
+ )
def get_default_deps(commands):
- if commands and any(c in str(commands) for c in ['pytest', 'py.test']):
- return ['pytest']
- if 'trial' in commands:
- return ['twisted']
+ if commands and any(c in str(commands) for c in ["pytest", "py.test"]):
+ return ["pytest"]
+ if "trial" in commands:
+ return ["twisted"]
return []
def post_process_input(map_):
envlist = [env for env in tox.PYTHON.QUICKSTART_PY_ENVS if map_.get(env) is True]
- map_['envlist'] = ', '.join(envlist)
- map_['commands'] = '\n '.join([cmd.strip() for cmd in map_['commands']])
- map_['deps'] = '\n '.join([dep.strip() for dep in set(map_['deps'])])
+ map_["envlist"] = ", ".join(envlist)
+ map_["commands"] = "\n ".join([cmd.strip() for cmd in map_["commands"]])
+ map_["deps"] = "\n ".join([dep.strip() for dep in set(map_["deps"])])
def generate(map_):
"""Generate project based on values in *d*."""
- dpath = map_.get('path', os.getcwd())
+ dpath = map_.get("path", os.getcwd())
altpath = os.path.join(dpath, ALTERNATIVE_CONFIG_NAME)
while True:
- name = map_.get('name', tox.INFO.DEFAULT_CONFIG_NAME)
+ name = map_.get("name", tox.INFO.DEFAULT_CONFIG_NAME)
targetpath = os.path.join(dpath, name)
if not os.path.isfile(targetpath):
break
- do_prompt(map_, 'name', '%s exists - choose an alternative' % targetpath, altpath)
- with codecs.open(targetpath, 'w', encoding='utf-8') as f:
+ do_prompt(map_, "name", "{} exists - choose an alternative".format(targetpath), altpath)
+ with codecs.open(targetpath, "w", encoding="utf-8") as f:
f.write(prepare_content(QUICKSTART_CONF.format(**map_)))
- print('Finished: %s has been created. For information on this file, '
- 'see https://tox.readthedocs.io/en/latest/config.html\n'
- 'Execute `tox` to test your project.' % targetpath)
+ print(
+ "Finished: {} has been created. For information on this file, "
+ "see https://tox.readthedocs.io/en/latest/config.html\n"
+ "Execute `tox` to test your project.".format(targetpath)
+ )
def prepare_content(content):
- return '\n'.join([line.rstrip() for line in content.split("\n")])
+ return "\n".join([line.rstrip() for line in content.split("\n")])
def parse_args():
parser = argparse.ArgumentParser(
- description='Command-line script to quickly tox config file for a Python project.')
+ description="Command-line script to quickly tox config file for a Python project."
+ )
parser.add_argument(
- 'root', type=str, nargs='?', default='.',
- help='Custom root directory to write config to. Defaults to current directory.')
- parser.add_argument('--version', action='version', version='%(prog)s ' + tox.__version__)
+ "root",
+ type=str,
+ nargs="?",
+ default=".",
+ help="Custom root directory to write config to. Defaults to current directory.",
+ )
+ parser.add_argument("--version", action="version", version="%(prog)s " + tox.__version__)
return parser.parse_args()
def main():
args = parse_args()
- map_ = {'path': args.root}
+ map_ = {"path": args.root}
try:
ask_user(map_)
except (KeyboardInterrupt, EOFError):
- print('\n[Interrupted.]')
+ print("\n[Interrupted.]")
return 1
post_process_input(map_)
generate(map_)
-if __name__ == '__main__':
+if __name__ == "__main__":
sys.exit(main())
diff --git a/tox/_verlib.py b/tox/_verlib.py
index 39294695..1c9c7f31 100644
--- a/tox/_verlib.py
+++ b/tox/_verlib.py
@@ -40,9 +40,10 @@ class HugeMajorVersionNumError(IrrationalVersionError):
# |
# 'dev' < 'f' ----------------------------------------------/
# Other letters would do, but 'f' for 'final' is kind of nice.
-FINAL_MARKER = ('f',)
+FINAL_MARKER = ("f",)
-VERSION_RE = re.compile(r'''
+VERSION_RE = re.compile(
+ r"""
^
(?P<version>\d+\.\d+) # minimum 'N.N'
(?P<extraversion>(?:\.\d+)*) # any number of extra '.N' segments
@@ -52,7 +53,9 @@ VERSION_RE = re.compile(r'''
(?P<prerelversion>\d+(?:\.\d+)*)
)?
(?P<postdev>(\.post(?P<post>\d+))?(\.dev(?P<dev>\d+))?)?
- $''', re.VERBOSE)
+ $""",
+ re.VERBOSE,
+)
class NormalizedVersion(object):
@@ -94,8 +97,7 @@ class NormalizedVersion(object):
self._parse(s, error_on_huge_major_num)
@classmethod
- def from_parts(cls, version, prerelease=FINAL_MARKER,
- devpost=FINAL_MARKER):
+ def from_parts(cls, version, prerelease=FINAL_MARKER, devpost=FINAL_MARKER):
return cls(cls.parts_to_str((version, prerelease, devpost)))
def _parse(self, s, error_on_huge_major_num=True):
@@ -108,44 +110,44 @@ class NormalizedVersion(object):
parts = []
# main version
- block = self._parse_numdots(groups['version'], s, False, 2)
- extraversion = groups.get('extraversion')
- if extraversion not in ('', None):
+ block = self._parse_numdots(groups["version"], s, False, 2)
+ extraversion = groups.get("extraversion")
+ if extraversion not in ("", None):
block += self._parse_numdots(extraversion[1:], s)
parts.append(tuple(block))
# prerelease
- prerel = groups.get('prerel')
+ prerel = groups.get("prerel")
if prerel is not None:
block = [prerel]
- block += self._parse_numdots(groups.get('prerelversion'), s,
- pad_zeros_length=1)
+ block += self._parse_numdots(groups.get("prerelversion"), s, pad_zeros_length=1)
parts.append(tuple(block))
else:
parts.append(FINAL_MARKER)
# postdev
- if groups.get('postdev'):
- post = groups.get('post')
- dev = groups.get('dev')
+ if groups.get("postdev"):
+ post = groups.get("post")
+ dev = groups.get("dev")
postdev = []
if post is not None:
- postdev.extend([FINAL_MARKER[0], 'post', int(post)])
+ postdev.extend([FINAL_MARKER[0], "post", int(post)])
if dev is None:
postdev.append(FINAL_MARKER[0])
if dev is not None:
- postdev.extend(['dev', int(dev)])
+ postdev.extend(["dev", int(dev)])
parts.append(tuple(postdev))
else:
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, "
- "which might cause future problems: %r" % (self.parts[0][0], s))
+ "huge major version number, {!r}, which might cause future problems: {!r}".format(
+ self.parts[0][0], s
+ )
+ )
- def _parse_numdots(self, s, full_ver_str, drop_trailing_zeros=True,
- pad_zeros_length=0):
+ def _parse_numdots(self, s, full_ver_str, drop_trailing_zeros=True, pad_zeros_length=0):
"""Parse 'N.N.N' sequences, return a list of ints.
@param s {str} 'N.N.N..." sequence to be parsed
@@ -158,10 +160,12 @@ class NormalizedVersion(object):
"""
nums = []
for n in s.split("."):
- if len(n) > 1 and n[0] == '0':
+ if len(n) > 1 and n[0] == "0":
raise IrrationalVersionError(
- "cannot have leading zero in "
- "version number segment: '%s' in %r" % (n, full_ver_str))
+ "cannot have leading zero in version number segment: '{}' in {!r}".format(
+ n, full_ver_str
+ )
+ )
nums.append(int(n))
if drop_trailing_zeros:
while nums and nums[-1] == 0:
@@ -178,27 +182,28 @@ class NormalizedVersion(object):
"""Transform a version expressed in tuple into its string representation."""
# FIXME XXX This doesn't check for invalid tuples
main, prerel, postdev = parts
- s = '.'.join(str(v) for v in main)
+ s = ".".join(str(v) for v in main)
if prerel is not FINAL_MARKER:
s += prerel[0]
- s += '.'.join(str(v) for v in prerel[1:])
+ s += ".".join(str(v) for v in prerel[1:])
if postdev and postdev is not FINAL_MARKER:
- if postdev[0] == 'f':
+ if postdev[0] == "f":
postdev = postdev[1:]
i = 0
while i < len(postdev):
if i % 2 == 0:
- s += '.'
+ s += "."
s += str(postdev[i])
i += 1
return s
def __repr__(self):
- return "%s('%s')" % (self.__class__.__name__, self)
+ return "{}('{}')".format(self.__class__.__name__, self)
def _cannot_compare(self, other):
- raise TypeError("cannot compare %s and %s"
- % (type(self).__name__, type(other).__name__))
+ raise TypeError(
+ "cannot compare {} and {}".format(type(self).__name__, type(other).__name__)
+ )
def __eq__(self, other):
if not isinstance(other, NormalizedVersion):
diff --git a/tox/config.py b/tox/config.py
index 67d3fbd7..b3b8a843 100755
--- a/tox/config.py
+++ b/tox/config.py
@@ -16,9 +16,8 @@ import pluggy
import py
import tox
-from tox.interpreters import Interpreters
from tox._verlib import NormalizedVersion
-
+from tox.interpreters import Interpreters
hookimpl = tox.hookimpl
"""DEPRECATED - REMOVE - this is left for compatibility with plugins importing this from here.
@@ -36,6 +35,7 @@ default_factors = tox.PYTHON.DEFAULT_FACTORS
def get_plugin_manager(plugins=()):
# initialize plugin manager
import tox.venv
+
pm = pluggy.PluginManager("tox")
pm.add_hookspecs(tox.hookspecs)
pm.register(tox.config)
@@ -51,9 +51,9 @@ def get_plugin_manager(plugins=()):
class Parser:
"""Command line and ini-parser control object."""
+
def __init__(self):
- self.argparser = argparse.ArgumentParser(
- description="tox options", add_help=False)
+ self.argparser = argparse.ArgumentParser(description="tox options", add_help=False)
self._testenv_attr = []
def add_argument(self, *args, **kwargs):
@@ -99,6 +99,7 @@ class Parser:
class VenvAttribute:
+
def __init__(self, name, type, default, help, postprocess):
self.name = name
self.type = type
@@ -129,11 +130,11 @@ class DepOption:
# in case of a short option, we remove the space
for option in tox.PIP.INSTALL_SHORT_OPTIONS_ARGUMENT:
if name.startswith(option):
- name = '%s%s' % (option, name[len(option):].strip())
+ name = "{}{}".format(option, name[len(option):].strip())
# in case of a long option, we add an equal sign
for option in tox.PIP.INSTALL_LONG_OPTIONS_ARGUMENT:
- if name.startswith(option + ' '):
- name = '%s=%s' % (option, name[len(option):].strip())
+ if name.startswith(option + " "):
+ name = "{}={}".format(option, name[len(option):].strip())
name = self._replace_forced_dep(name, config)
deps.append(DepConfig(name, ixserver))
return deps
@@ -193,9 +194,10 @@ class InstallcmdOption:
help = "install command for dependencies and package under test."
def postprocess(self, testenv_config, value):
- if '{packages}' not in value:
+ if "{packages}" not in value:
raise tox.exception.ConfigError(
- "'install_command' must contain '{packages}' substitution")
+ "'install_command' must contain '{packages}' substitution"
+ )
return value
@@ -226,18 +228,17 @@ def parseconfig(args, plugins=()):
inipath = py.path.local(basename)
elif os.path.isdir(basename):
# Assume 'tox.ini' filename if directory was passed
- inipath = py.path.local(os.path.join(basename, 'tox.ini'))
+ inipath = py.path.local(os.path.join(basename, "tox.ini"))
else:
for path in py.path.local().parts(reverse=True):
inipath = path.join(basename)
if inipath.check():
break
else:
- inipath = py.path.local().join('setup.cfg')
+ inipath = py.path.local().join("setup.cfg")
if not inipath.check():
helpoptions = option.help or option.helpini
- feedback("toxini file %r not found" % (basename),
- sysexit=not helpoptions)
+ feedback("toxini file {!r} not found".format(basename), sysexit=not helpoptions)
if helpoptions:
return config
@@ -246,7 +247,7 @@ def parseconfig(args, plugins=()):
except tox.exception.InterpreterNotFound:
exn = sys.exc_info()[1]
# Use stdout to match test expectations
- print("ERROR: " + str(exn))
+ print("ERROR: {}".format(exn))
# post process config object
pm.hook.tox_configure(config=config)
@@ -261,15 +262,14 @@ def feedback(msg, sysexit=False):
def get_version_info(pm):
- out = ["%s imported from %s" % (tox.__version__, tox.__file__)]
+ out = ["{} imported from {}".format(tox.__version__, tox.__file__)]
plugin_dist_info = pm.list_plugin_distinfo()
if plugin_dist_info:
- out.append('registered plugins:')
+ out.append("registered plugins:")
for mod, egg_info in plugin_dist_info:
- source = getattr(mod, '__file__', repr(mod))
- out.append(" %s-%s at %s" % (
- egg_info.project_name, egg_info.version, source))
- return '\n'.join(out)
+ source = getattr(mod, "__file__", repr(mod))
+ out.append(" {}-{} at {}".format(egg_info.project_name, egg_info.version, source))
+ return "\n".join(out)
class SetenvDict(object):
@@ -282,7 +282,7 @@ class SetenvDict(object):
self._lookupstack = []
def __repr__(self):
- return "%s: %s" % (self.__class__.__name__, self.definitions)
+ return "{}: {}".format(self.__class__.__name__, self.definitions)
def __contains__(self, name):
return name in self.definitions
@@ -321,100 +321,189 @@ class SetenvDict(object):
@tox.hookimpl
def tox_addoption(parser):
# formatter_class=argparse.ArgumentDefaultsHelpFormatter)
- parser.add_argument("--version", action="store_true", dest="version",
- help="report version information to stdout.")
- parser.add_argument("-h", "--help", action="store_true", dest="help",
- help="show help about options")
- parser.add_argument("--help-ini", "--hi", action="store_true", dest="helpini",
- help="show help about ini-names")
- parser.add_argument("-v", action='count', dest="verbose_level", default=0,
- help="increase verbosity of reporting output. -vv mode turns off "
- "output redirection for package installation")
- parser.add_argument("-q", action="count", dest="quiet_level", default=0,
- help="progressively silence reporting output.")
- parser.add_argument("--showconfig", action="store_true",
- help="show configuration information for all environments. ")
- parser.add_argument("-l", "--listenvs", action="store_true",
- dest="listenvs", help="show list of test environments "
- "(with description if verbose)")
- parser.add_argument("-a", "--listenvs-all", action="store_true",
- dest="listenvs_all",
- help="show list of all defined environments"
- "(with description if verbose)")
- parser.add_argument("-c", action="store", default="tox.ini",
- dest="configfile",
- help="config file name or directory with 'tox.ini' file.")
- parser.add_argument("-e", action="append", dest="env",
- metavar="envlist",
- help="work against specified environments (ALL selects all).")
- parser.add_argument("--notest", action="store_true", dest="notest",
- help="skip invoking test commands.")
- parser.add_argument("--sdistonly", action="store_true", dest="sdistonly",
- 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.")
- parser.add_argument("--develop", action="store_true", dest="develop",
- help="install package in the venv using 'setup.py develop' via "
- "'pip -e .'")
- parser.add_argument('-i', '--index-url', 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)")
- 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).")
- parser.add_argument("-r", "--recreate", action="store_true",
- 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.")
+ parser.add_argument(
+ "--version",
+ action="store_true",
+ dest="version",
+ help="report version information to stdout.",
+ )
+ parser.add_argument(
+ "-h", "--help", action="store_true", dest="help", help="show help about options"
+ )
+ parser.add_argument(
+ "--help-ini", "--hi", action="store_true", dest="helpini", help="show help about ini-names"
+ )
+ parser.add_argument(
+ "-v",
+ action="count",
+ dest="verbose_level",
+ default=0,
+ help="increase verbosity of reporting output. -vv mode turns off "
+ "output redirection for package installation",
+ )
+ parser.add_argument(
+ "-q",
+ action="count",
+ dest="quiet_level",
+ default=0,
+ help="progressively silence reporting output.",
+ )
+ parser.add_argument(
+ "--showconfig",
+ action="store_true",
+ help="show configuration information for all environments. ",
+ )
+ parser.add_argument(
+ "-l",
+ "--listenvs",
+ action="store_true",
+ dest="listenvs",
+ help="show list of test environments (with description if verbose)",
+ )
+ parser.add_argument(
+ "-a",
+ "--listenvs-all",
+ action="store_true",
+ dest="listenvs_all",
+ help="show list of all defined environments (with description if verbose)",
+ )
+ parser.add_argument(
+ "-c",
+ action="store",
+ default="tox.ini",
+ dest="configfile",
+ help="config file name or directory with 'tox.ini' file.",
+ )
+ parser.add_argument(
+ "-e",
+ action="append",
+ dest="env",
+ metavar="envlist",
+ help="work against specified environments (ALL selects all).",
+ )
+ parser.add_argument(
+ "--notest", action="store_true", dest="notest", help="skip invoking test commands."
+ )
+ parser.add_argument(
+ "--sdistonly",
+ action="store_true",
+ dest="sdistonly",
+ 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.",
+ )
+ parser.add_argument(
+ "--develop",
+ action="store_true",
+ dest="develop",
+ help="install package in the venv using 'setup.py develop' via 'pip -e .'",
+ )
+ parser.add_argument(
+ "-i",
+ "--index-url",
+ 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)",
+ )
+ 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).",
+ )
+ parser.add_argument(
+ "-r",
+ "--recreate",
+ action="store_true",
+ 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.",
+ )
# 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.")
- 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'.")
- parser.add_argument("--sitepackages", action="store_true",
- help="override sitepackages setting to True in all envs")
- parser.add_argument("--alwayscopy", action="store_true",
- help="override alwayscopy 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")
+ 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.",
+ )
+ 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'.",
+ )
+ parser.add_argument(
+ "--sitepackages",
+ action="store_true",
+ help="override sitepackages setting to True in all envs",
+ )
+ parser.add_argument(
+ "--alwayscopy", action="store_true", help="override alwayscopy 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"
+ )
parser.add_testenv_attribute(
- name="envdir", type="path", default="{toxworkdir}/{envname}",
+ name="envdir",
+ type="path",
+ default="{toxworkdir}/{envname}",
help="set venv directory -- be very careful when changing this as tox "
- "will remove this directory when recreating an environment")
+ "will remove this directory when recreating an environment",
+ )
# add various core venv interpreter attributes
def setenv(testenv_config, value):
setenv = value
config = testenv_config.config
if "PYTHONHASHSEED" not in setenv and config.hashseed is not None:
- setenv['PYTHONHASHSEED'] = config.hashseed
+ setenv["PYTHONHASHSEED"] = config.hashseed
return setenv
parser.add_testenv_attribute(
- name="setenv", type="dict_setenv", postprocess=setenv,
- help="list of X=Y lines with environment variable settings")
+ name="setenv",
+ type="dict_setenv",
+ postprocess=setenv,
+ help="list of X=Y lines with environment variable settings",
+ )
def basepython_default(testenv_config, value):
if value is None:
@@ -425,47 +514,65 @@ def tox_addoption(parser):
return str(value)
parser.add_testenv_attribute(
- name="basepython", type="string", default=None, postprocess=basepython_default,
- help="executable name or path of interpreter used to create a "
- "virtual test environment.")
+ name="basepython",
+ type="string",
+ default=None,
+ postprocess=basepython_default,
+ help="executable name or path of interpreter used to create a virtual test environment.",
+ )
def merge_description(testenv_config, value):
"""the reader by default joins generated description with new line,
replace new line with space"""
- return value.replace('\n', ' ')
+ return value.replace("\n", " ")
parser.add_testenv_attribute(
- name="description", type="string", default='', postprocess=merge_description,
- help="short description of this environment")
+ name="description",
+ type="string",
+ default="",
+ postprocess=merge_description,
+ help="short description of this environment",
+ )
parser.add_testenv_attribute(
- name="envtmpdir", type="path", default="{envdir}/tmp",
- help="venv temporary directory")
+ name="envtmpdir", type="path", default="{envdir}/tmp", help="venv temporary directory"
+ )
parser.add_testenv_attribute(
- name="envlogdir", type="path", default="{envdir}/log",
- help="venv log directory")
+ name="envlogdir", type="path", default="{envdir}/log", help="venv log directory"
+ )
parser.add_testenv_attribute(
- name="downloadcache", type="string", default=None,
- help="(ignored) has no effect anymore, pip-8 uses local caching by default")
+ name="downloadcache",
+ type="string",
+ default=None,
+ help="(ignored) has no effect anymore, pip-8 uses local caching by default",
+ )
parser.add_testenv_attribute(
- name="changedir", type="path", default="{toxinidir}",
- help="directory to change to when running commands")
+ name="changedir",
+ type="path",
+ default="{toxinidir}",
+ help="directory to change to when running commands",
+ )
parser.add_testenv_attribute_obj(PosargsOption())
parser.add_testenv_attribute(
- name="skip_install", type="bool", default=False,
- help="Do not install the current package. This can be used when "
- "you need the virtualenv management but do not want to install "
- "the current package")
+ name="skip_install",
+ type="bool",
+ default=False,
+ help="Do not install the current package. This can be used when you need the virtualenv "
+ "management but do not want to install the current package",
+ )
parser.add_testenv_attribute(
- name="ignore_errors", type="bool", default=False,
- help="if set to True all commands will be executed irrespective of their "
- "result error status.")
+ name="ignore_errors",
+ type="bool",
+ default=False,
+ help="if set to True all commands will be executed irrespective of their result error "
+ "status.",
+ )
def recreate(testenv_config, value):
if testenv_config.config.option.recreate:
@@ -473,18 +580,18 @@ def tox_addoption(parser):
return value
parser.add_testenv_attribute(
- name="recreate", type="bool", default=False, postprocess=recreate,
- help="always recreate this test environment.")
+ name="recreate",
+ type="bool",
+ default=False,
+ postprocess=recreate,
+ help="always recreate this test environment.",
+ )
def passenv(testenv_config, value):
# Flatten the list to deal with space-separated values.
- value = list(
- itertools.chain.from_iterable(
- [x.split(' ') for x in value]))
+ value = list(itertools.chain.from_iterable([x.split(" ") for x in value]))
- passenv = {
- "PATH", "PIP_INDEX_URL", "LANG", "LANGUAGE", "LD_LIBRARY_PATH"
- }
+ passenv = {"PATH", "PIP_INDEX_URL", "LANG", "LANGUAGE", "LD_LIBRARY_PATH"}
# read in global passenv settings
p = os.environ.get("TOX_TESTENV_PASSENV", None)
@@ -517,22 +624,29 @@ def tox_addoption(parser):
return passenv
parser.add_testenv_attribute(
- name="passenv", type="line-list", postprocess=passenv,
- help="environment variables needed during executing test commands "
- "(taken from invocation environment). Note that tox always "
- "passes through some basic environment variables which are "
- "needed for basic functioning of the Python system. "
- "See --showconfig for the eventual passenv setting.")
+ name="passenv",
+ type="line-list",
+ postprocess=passenv,
+ help="environment variables needed during executing test commands (taken from invocation "
+ "environment). Note that tox always passes through some basic environment variables "
+ "which are needed for basic functioning of the Python system. See --showconfig for the "
+ "eventual passenv setting.",
+ )
parser.add_testenv_attribute(
- name="whitelist_externals", type="line-list",
+ name="whitelist_externals",
+ type="line-list",
help="each lines specifies a path or basename for which tox will not warn "
- "about it coming from outside the test environment.")
+ "about it coming from outside the test environment.",
+ )
parser.add_testenv_attribute(
- name="platform", type="string", default=".*",
+ name="platform",
+ type="string",
+ default=".*",
help="regular expression which must match against ``sys.platform``. "
- "otherwise testenv will be skipped.")
+ "otherwise testenv will be skipped.",
+ )
def sitepackages(testenv_config, value):
return testenv_config.config.option.sitepackages or value
@@ -541,30 +655,45 @@ def tox_addoption(parser):
return testenv_config.config.option.alwayscopy or value
parser.add_testenv_attribute(
- name="sitepackages", type="bool", default=False, postprocess=sitepackages,
+ name="sitepackages",
+ type="bool",
+ default=False,
+ postprocess=sitepackages,
help="Set to ``True`` if you want to create virtual environments that also "
- "have access to globally installed packages.")
+ "have access to globally installed packages.",
+ )
parser.add_testenv_attribute(
- name="alwayscopy", type="bool", default=False, postprocess=alwayscopy,
+ name="alwayscopy",
+ type="bool",
+ default=False,
+ postprocess=alwayscopy,
help="Set to ``True`` if you want virtualenv to always copy files rather "
- "than symlinking.")
+ "than symlinking.",
+ )
def pip_pre(testenv_config, value):
return testenv_config.config.option.pre or value
parser.add_testenv_attribute(
- name="pip_pre", type="bool", default=False, postprocess=pip_pre,
- help="If ``True``, adds ``--pre`` to the ``opts`` passed to "
- "the install command. ")
+ name="pip_pre",
+ type="bool",
+ default=False,
+ postprocess=pip_pre,
+ help="If ``True``, adds ``--pre`` to the ``opts`` passed to the install command. ",
+ )
def develop(testenv_config, value):
option = testenv_config.config.option
return not option.installpkg and (value or option.develop)
parser.add_testenv_attribute(
- name="usedevelop", type="bool", postprocess=develop, default=False,
- help="install package in develop/editable mode")
+ name="usedevelop",
+ type="bool",
+ postprocess=develop,
+ default=False,
+ help="install package in develop/editable mode",
+ )
parser.add_testenv_attribute_obj(InstallcmdOption())
@@ -572,27 +701,36 @@ def tox_addoption(parser):
name="list_dependencies_command",
type="argv",
default="pip freeze",
- help="list dependencies for a virtual environment")
+ help="list dependencies for a virtual environment",
+ )
parser.add_testenv_attribute_obj(DepOption())
parser.add_testenv_attribute(
- name="commands", type="argvlist", default="",
- help="each line specifies a test command and can use substitution.")
+ name="commands",
+ type="argvlist",
+ default="",
+ help="each line specifies a test command and can use substitution.",
+ )
parser.add_testenv_attribute(
- "ignore_outcome", type="bool", default=False,
+ "ignore_outcome",
+ type="bool",
+ default=False,
help="if set to True a failing result of this testenv will not make "
- "tox fail, only a warning will be produced")
+ "tox fail, only a warning will be produced",
+ )
parser.add_testenv_attribute(
- "extras", type="line-list",
- help="list of extras to install with the source distribution or "
- "develop install")
+ "extras",
+ type="line-list",
+ help="list of extras to install with the source distribution or develop install",
+ )
class Config(object):
"""Global Tox config object."""
+
def __init__(self, pluginmanager, option, interpreters):
self.envconfigs = {}
"""Mapping envname -> envconfig"""
@@ -616,6 +754,7 @@ class TestenvConfig:
In addition to some core attributes/properties this config object holds all
per-testenv ini attributes as attributes, see "tox --help-ini" for an overview.
"""
+
def __init__(self, envname, config, factors, reader):
#: test environment name
self.envname = envname
@@ -634,9 +773,7 @@ class TestenvConfig:
def get_envbindir(self):
"""Path to directory where scripts/binaries reside."""
- if (tox.INFO.IS_WIN and
- "jython" not in self.basepython and
- "pypy" not in self.basepython):
+ if tox.INFO.IS_WIN and "jython" not in self.basepython and "pypy" not in self.basepython:
return self.envdir.join("Scripts")
else:
return self.envdir.join("bin")
@@ -663,9 +800,7 @@ class TestenvConfig:
NOTE: Only available during execution, not during parsing.
"""
- x = self.config.interpreters.get_sitepackagesdir(
- info=self.python_info,
- envdir=self.envdir)
+ x = self.config.interpreters.get_sitepackagesdir(info=self.python_info, envdir=self.envdir)
return x
@property
@@ -676,13 +811,15 @@ class TestenvConfig:
def getsupportedinterpreter(self):
if tox.INFO.IS_WIN and self.basepython and "jython" in self.basepython:
raise tox.exception.UnsupportedInterpreter(
- "Jython/Windows does not support installing scripts")
+ "Jython/Windows does not support installing scripts"
+ )
info = self.config.interpreters.get_info(envconfig=self)
if not info.executable:
raise tox.exception.InterpreterNotFound(self.basepython)
if not info.version_info:
raise tox.exception.InvocationError(
- 'Failed to get version_info for %s: %s' % (info.name, info.err))
+ "Failed to get version_info for {}: {}".format(info.name, info.err)
+ )
return info.executable
@@ -704,6 +841,7 @@ def make_hashseed():
class parseini:
+
def __init__(self, config, inipath):
config.toxinipath = inipath
config.toxinidir = config.toxinipath.dirpath()
@@ -712,14 +850,15 @@ class parseini:
config._cfg = self._cfg
self.config = config
- if inipath.basename == 'setup.cfg':
- prefix = 'tox'
+ if inipath.basename == "setup.cfg":
+ prefix = "tox"
else:
prefix = None
ctxname = getcontextname()
if ctxname == "jenkins":
- reader = SectionReader("tox:jenkins", self._cfg, prefix=prefix,
- fallbacksections=['tox'])
+ reader = SectionReader(
+ "tox:jenkins", self._cfg, prefix=prefix, fallbacksections=["tox"]
+ )
distshare_default = "{toxworkdir}/distshare"
elif not ctxname:
reader = SectionReader("tox", self._cfg, prefix=prefix)
@@ -729,14 +868,13 @@ class parseini:
if config.option.hashseed is None:
hashseed = make_hashseed()
- elif config.option.hashseed == 'noset':
+ elif config.option.hashseed == "noset":
hashseed = None
else:
hashseed = config.option.hashseed
config.hashseed = hashseed
- reader.addsubstitutions(toxinidir=config.toxinidir,
- homedir=config.homedir)
+ reader.addsubstitutions(toxinidir=config.toxinidir, homedir=config.homedir)
# As older versions of tox may have bugs or incompatibilities that
# prevent parsing of tox.ini this must be the first thing checked.
config.minversion = reader.getstring("minversion", None)
@@ -745,19 +883,20 @@ class parseini:
toxversion = NormalizedVersion(tox.__version__)
if toxversion < minversion:
raise tox.exception.MinVersionError(
- "tox version is %s, required is at least %s" % (
- toxversion, minversion))
+ "tox version is {}, required is at least {}".format(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 = \
- reader.getbool("skip_missing_interpreters", False)
+ config.option.skip_missing_interpreters = reader.getbool(
+ "skip_missing_interpreters", False
+ )
# determine indexserver dictionary
- config.indexserver = {'default': IndexServerConfig('default')}
+ config.indexserver = {"default": IndexServerConfig("default")}
prefix = "indexserver"
for line in reader.getlist(prefix):
name, url = map(lambda x: x.strip(), line.split("=", 1))
@@ -803,17 +942,19 @@ class parseini:
stated_envlist = reader.getstring("envlist", replace=False)
if stated_envlist:
for env in _split_env(stated_envlist):
- known_factors.update(env.split('-'))
+ known_factors.update(env.split("-"))
# configure testenvs
for name in all_envs:
section = testenvprefix + name
- factors = set(name.split('-'))
+ factors = set(name.split("-"))
if section in self._cfg or factors <= known_factors:
config.envconfigs[name] = self.make_envconfig(name, section, reader._subs, config)
- all_develop = all(name in config.envconfigs and
- config.envconfigs[name].usedevelop for name in config.envlist)
+ all_develop = all(
+ name in config.envconfigs and config.envconfigs[name].usedevelop
+ for name in config.envlist
+ )
config.skipsdist = reader.getbool("skipsdist", all_develop)
@@ -821,18 +962,21 @@ class parseini:
factors = set()
if section in self._cfg:
for _, value in self._cfg[section].items():
- exprs = re.findall(r'^([\w{}\.!,-]+)\:\s+', value, re.M)
+ exprs = re.findall(r"^([\w{}\.!,-]+)\:\s+", value, re.M)
factors.update(*mapcat(_split_factor_expr_all, exprs))
return factors
def make_envconfig(self, name, section, subs, config, replace=True):
- factors = set(name.split('-'))
- reader = SectionReader(section, self._cfg, fallbacksections=["testenv"],
- factors=factors)
+ factors = set(name.split("-"))
+ reader = SectionReader(section, self._cfg, fallbacksections=["testenv"], factors=factors)
tc = TestenvConfig(name, config, factors, reader)
reader.addsubstitutions(
- envname=name, envbindir=tc.get_envbindir, envsitepackagesdir=tc.get_envsitepackagesdir,
- envpython=tc.get_envpython, **subs)
+ envname=name,
+ envbindir=tc.get_envbindir,
+ envsitepackagesdir=tc.get_envsitepackagesdir,
+ envpython=tc.get_envpython,
+ **subs
+ )
for env_attr in config._testenv_attr:
atype = env_attr.type
try:
@@ -844,7 +988,7 @@ class parseini:
elif atype == "line-list":
res = reader.getlist(env_attr.name, sep="\n")
else:
- raise ValueError("unknown type %r" % (atype,))
+ raise ValueError("unknown type {!r}".format(atype))
if env_attr.postprocess:
res = env_attr.postprocess(testenv_config=tc, value=res)
except tox.exception.MissingSubstitution as e:
@@ -856,37 +1000,39 @@ class parseini:
return tc
def _getenvdata(self, reader):
- envstr = self.config.option.env \
- or os.environ.get("TOXENV") \
- or reader.getstring("envlist", replace=False) \
- or []
- envlist = _split_env(envstr)
+ candidates = (
+ self.config.option.env,
+ os.environ.get("TOXENV"),
+ reader.getstring("envlist", replace=False),
+ )
+ env_str = next((i for i in candidates if i), [])
+ env_list = _split_env(env_str)
# collect section envs
- all_envs = set(envlist) - {"ALL"}
+ all_envs = set(env_list) - {"ALL"}
for section in self._cfg:
if section.name.startswith(testenvprefix):
all_envs.add(section.name[len(testenvprefix):])
if not all_envs:
all_envs.add("python")
- if not envlist or "ALL" in envlist:
- envlist = sorted(all_envs)
+ if not env_list or "ALL" in env_list:
+ env_list = sorted(all_envs)
- return envlist, all_envs
+ return env_list, all_envs
def _split_env(env):
"""if handed a list, action="append" was used for -e """
if not isinstance(env, list):
- env = [e.split('#', 1)[0].strip() for e in env.split('\n')]
- env = ','.join([e for e in env if e])
+ env = [e.split("#", 1)[0].strip() for e in env.split("\n")]
+ env = ",".join([e for e in env if e])
env = [env]
return mapcat(_expand_envstr, env)
def _is_negated_factor(factor):
- return factor.startswith('!')
+ return factor.startswith("!")
def _base_factor_name(factor):
@@ -894,12 +1040,11 @@ def _base_factor_name(factor):
def _split_factor_expr(expr):
+
def split_single(e):
- raw = e.split('-')
- included = {_base_factor_name(factor) for factor in raw
- if not _is_negated_factor(factor)}
- excluded = {_base_factor_name(factor) for factor in raw
- if _is_negated_factor(factor)}
+ raw = e.split("-")
+ included = {_base_factor_name(factor) for factor in raw if not _is_negated_factor(factor)}
+ excluded = {_base_factor_name(factor) for factor in raw if _is_negated_factor(factor)}
return included, excluded
partial_envs = _expand_envstr(expr)
@@ -908,20 +1053,18 @@ def _split_factor_expr(expr):
def _split_factor_expr_all(expr):
partial_envs = _expand_envstr(expr)
- return [{_base_factor_name(factor) for factor in e.split('-')}
- for e in partial_envs]
+ return [{_base_factor_name(factor) for factor in e.split("-")} for e in partial_envs]
def _expand_envstr(envstr):
# split by commas not in groups
- tokens = re.split(r'((?:\{[^}]+\})+)|,', envstr)
- envlist = [''.join(g).strip()
- for k, g in itertools.groupby(tokens, key=bool) if k]
+ tokens = re.split(r"((?:\{[^}]+\})+)|,", envstr)
+ envlist = ["".join(g).strip() for k, g in itertools.groupby(tokens, key=bool) if k]
def expand(env):
- tokens = re.split(r'\{([^}]+)\}', env)
- parts = [re.sub('\s+', '', token).split(',') for token in tokens]
- return [''.join(variant) for variant in itertools.product(*parts)]
+ tokens = re.split(r"\{([^}]+)\}", env)
+ parts = [re.sub("\s+", "", token).split(",") for token in tokens]
+ return ["".join(variant) for variant in itertools.product(*parts)]
return mapcat(expand, envlist)
@@ -931,6 +1074,7 @@ def mapcat(f, seq):
class DepConfig:
+
def __init__(self, name, indexserver=None):
self.name = name
self.indexserver = indexserver
@@ -939,13 +1083,14 @@ class DepConfig:
if self.indexserver:
if self.indexserver.name == "default":
return self.name
- return ":%s:%s" % (self.indexserver.name, self.name)
+ return ":{}:{}".format(self.indexserver.name, self.name)
return str(self.name)
__repr__ = __str__
class IndexServerConfig:
+
def __init__(self, name, url=None):
self.name = name
self.url = url
@@ -959,12 +1104,12 @@ E.g. {[base]commands}
class SectionReader:
- def __init__(self, section_name, cfgparser, fallbacksections=None,
- factors=(), prefix=None):
+
+ 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.section_name = "{}:{}".format(prefix, section_name)
self._cfg = cfgparser
self.fallbacksections = fallbacksections or []
self.factors = factors
@@ -985,7 +1130,7 @@ class SectionReader:
def getpath(self, name, defaultpath, replace=True):
path = self.getstring(name, defaultpath, replace=replace)
if path is not None:
- toxinidir = self._subs['toxinidir']
+ toxinidir = self._subs["toxinidir"]
return toxinidir.join(path, abs=True)
def getlist(self, name, sep="\n"):
@@ -1011,7 +1156,7 @@ class SectionReader:
d = {}
for line in value.split(sep):
if line.strip():
- name, rest = line.split('=', 1)
+ name, rest = line.split("=", 1)
d[name.strip()] = rest.strip()
return d
@@ -1021,8 +1166,7 @@ class SectionReader:
if not s or not replace:
s = default
if s is None:
- raise KeyError("no config value [%s] %s found" % (
- self.section_name, name))
+ raise KeyError("no config value [{}] {} found".format(self.section_name, name))
if not isinstance(s, bool):
if s.lower() == "true":
@@ -1030,8 +1174,7 @@ class SectionReader:
elif s.lower() == "false":
s = False
else:
- raise tox.exception.ConfigError(
- "boolean value %r needs to be 'True' or 'False'")
+ raise tox.exception.ConfigError("boolean value %r needs to be 'True' or 'False'")
return s
def getargvlist(self, name, default="", replace=True):
@@ -1061,22 +1204,24 @@ class SectionReader:
return x
def _apply_factors(self, s):
+
def factor_line(line):
- m = re.search(r'^([\w{}\.!,-]+)\:\s+(.+)', line)
+ m = re.search(r"^([\w{}\.!,-]+)\:\s+(.+)", line)
if not m:
return line
expr, line = m.groups()
- if any(included <= self.factors and not
- any(x in self.factors for x in excluded)
- for included, excluded in _split_factor_expr(expr)):
+ if any(
+ included <= self.factors and not any(x in self.factors for x in excluded)
+ for included, excluded in _split_factor_expr(expr)
+ ):
return line
lines = s.strip().splitlines()
- return '\n'.join(filter(None, map(factor_line, lines)))
+ return "\n".join(filter(None, map(factor_line, lines)))
def _replace(self, value, name=None, section_name=None, crossonly=False):
- if '{' not in value:
+ if "{" not in value:
return value
section_name = section_name if section_name else self.section_name
@@ -1087,35 +1232,38 @@ class SectionReader:
except tox.exception.MissingSubstitution:
if not section_name.startswith(testenvprefix):
raise tox.exception.ConfigError(
- "substitution env:%r: unknown or recursive definition in "
- "section %r." % (value, section_name))
+ "substitution env:{!r}: unknown or recursive definition in"
+ " section {!r}.".format(value, section_name)
+ )
raise
return replaced
def _replace_if_needed(self, x, name, replace, crossonly):
- if replace and x and hasattr(x, 'replace'):
+ if replace and x and hasattr(x, "replace"):
x = self._replace(x, name=name, crossonly=crossonly)
return x
class Replacer:
RE_ITEM_REF = re.compile(
- r'''
+ r"""
(?<!\\)[{]
(?:(?P<sub_type>[^[:{}]+):)? # optional sub_type for special rules
(?P<substitution_value>(?:\[[^,{}]*\])?[^:,{}]*) # substitution key
(?::(?P<default_value>[^{}]*))? # default value
[}]
- ''', re.VERBOSE)
+ """,
+ re.VERBOSE,
+ )
def __init__(self, reader, crossonly=False):
self.reader = reader
self.crossonly = crossonly
def do_replace(self, value):
- '''
+ """
Recursively expand substitutions starting from the innermost expression
- '''
+ """
def substitute_once(x):
return self.RE_ITEM_REF.sub(self._replace_match, x)
@@ -1130,7 +1278,7 @@ class Replacer:
def _replace_match(self, match):
g = match.groupdict()
- sub_value = g['substitution_value']
+ sub_value = g["substitution_value"]
if self.crossonly:
if sub_value.startswith("["):
return self._substitute_from_other_section(sub_value)
@@ -1145,27 +1293,29 @@ class Replacer:
# special case: opts and packages. Leave {opts} and
# {packages} intact, they are replaced manually in
# _venv.VirtualEnv.run_install_command.
- if sub_value in ('opts', 'packages'):
- return '{%s}' % sub_value
+ if sub_value in ("opts", "packages"):
+ return "{{{}}}".format(sub_value)
try:
- sub_type = g['sub_type']
+ sub_type = g["sub_type"]
except KeyError:
raise tox.exception.ConfigError(
- "Malformed substitution; no substitution type provided")
+ "Malformed substitution; no substitution type provided"
+ )
if sub_type == "env":
return self._replace_env(match)
if sub_type is not None:
raise tox.exception.ConfigError(
- "No support for the %s substitution type" % sub_type)
+ "No support for the {} substitution type".format(sub_type)
+ )
return self._replace_substitution(match)
def _replace_env(self, match):
- envkey = match.group('substitution_value')
+ envkey = match.group("substitution_value")
if not envkey:
- raise tox.exception.ConfigError('env: requires an environment variable name')
- default = match.group('default_value')
+ raise tox.exception.ConfigError("env: requires an environment variable name")
+ default = match.group("default_value")
envvalue = self.reader.get_environ_value(envkey)
if envvalue is not None:
return envvalue
@@ -1180,17 +1330,18 @@ class Replacer:
cfg = self.reader._cfg
if section in cfg and item in cfg[section]:
if (section, item) in self.reader._subststack:
- raise ValueError('%s already in %s' % (
- (section, item), self.reader._subststack))
+ raise ValueError(
+ "{} already in {}".format((section, item), self.reader._subststack)
+ )
x = str(cfg[section][item])
- return self.reader._replace(x, name=item, section_name=section,
- crossonly=self.crossonly)
+ return self.reader._replace(
+ x, name=item, section_name=section, crossonly=self.crossonly
+ )
- raise tox.exception.ConfigError(
- "substitution key %r not found" % key)
+ raise tox.exception.ConfigError("substitution key {!r} not found".format(key))
def _replace_substitution(self, match):
- sub_key = match.group('substitution_value')
+ sub_key = match.group("substitution_value")
val = self.reader._subs.get(sub_key, None)
if val is None:
val = self._substitute_from_other_section(sub_key)
@@ -1200,6 +1351,7 @@ class Replacer:
class _ArgvlistReader:
+
@classmethod
def getargvlist(cls, reader, value, replace=True):
"""Parse ``commands`` argvlist multiline string.
@@ -1231,8 +1383,10 @@ class _ArgvlistReader:
else:
if current_command:
raise tox.exception.ConfigError(
- "line-continuation ends nowhere while resolving for [%s] %s" %
- (reader.section_name, "commands"))
+ "line-continuation ends nowhere while resolving for [{}] {}".format(
+ reader.section_name, "commands"
+ )
+ )
return commands
@classmethod
@@ -1259,7 +1413,7 @@ class _ArgvlistReader:
new_arg = ""
new_word = reader._replace(word)
new_word = reader._replace(new_word)
- new_word = new_word.replace('\\{', '{').replace('\\}', '}')
+ new_word = new_word.replace("\\{", "{").replace("\\}", "}")
new_arg += new_word
newcommand += new_arg
else:
@@ -1269,14 +1423,16 @@ class _ArgvlistReader:
# use all values as is in argv.
shlexer = shlex.shlex(newcommand, posix=True)
shlexer.whitespace_split = True
- shlexer.escape = ''
+ shlexer.escape = ""
return list(shlexer)
class CommandParser(object):
+
class State(object):
+
def __init__(self):
- self.word = ''
+ self.word = ""
self.depth = 0
self.yield_words = []
@@ -1287,16 +1443,20 @@ class CommandParser(object):
ps = CommandParser.State()
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() == ''))
+ 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() == "")
+ )
def yield_this_word():
yieldword = ps.word
- ps.word = ''
+ ps.word = ""
if yieldword:
ps.yield_words.append(yieldword)
@@ -1318,11 +1478,11 @@ class CommandParser(object):
if ps.depth == 0:
yield_if_word_ended()
accumulate()
- elif cur_char == '{':
+ elif cur_char == "{":
yield_if_word_ended()
accumulate()
push_substitution()
- elif cur_char == '}':
+ elif cur_char == "}":
accumulate()
pop_substitution()
else:
@@ -1335,6 +1495,6 @@ class CommandParser(object):
def getcontextname():
- if any(env in os.environ for env in ['JENKINS_URL', 'HUDSON_URL']):
- return 'jenkins'
+ if any(env in os.environ for env in ["JENKINS_URL", "HUDSON_URL"]):
+ return "jenkins"
return None
diff --git a/tox/constants.py b/tox/constants.py
index 1eaf6430..049a08dc 100644
--- a/tox/constants.py
+++ b/tox/constants.py
@@ -5,56 +5,60 @@ They live in the tox namespace and can be accessed as tox.[NAMESPACE.]NAME
import sys as _sys
-def _contruct_default_factors(version_tuples, other_interpreters):
- default_factors = {'py': _sys.executable, 'py2': 'python2', 'py3': 'python3'}
- default_factors.update({'py%s%s' % (major, minor): 'python%s.%s' % (major, minor)
- for major, minor in version_tuples})
+def _construct_default_factors(version_tuples, other_interpreters):
+ default_factors = {"py": _sys.executable, "py2": "python2", "py3": "python3"}
+ default_factors.update(
+ {
+ "py{}{}".format(major, minor): "python{}.{}".format(major, minor)
+ for major, minor in version_tuples
+ }
+ )
default_factors.update({interpreter: interpreter for interpreter in other_interpreters})
return default_factors
class PYTHON:
CPYTHON_VERSION_TUPLES = [(2, 7), (3, 4), (3, 5), (3, 6), (3, 7)]
- OTHER_PYTHON_INTERPRETERS = ['jython', 'pypy', 'pypy3']
- DEFAULT_FACTORS = _contruct_default_factors(CPYTHON_VERSION_TUPLES, OTHER_PYTHON_INTERPRETERS)
- CURRENT_RELEASE_ENV = 'py36'
+ OTHER_PYTHON_INTERPRETERS = ["jython", "pypy", "pypy3"]
+ DEFAULT_FACTORS = _construct_default_factors(CPYTHON_VERSION_TUPLES, OTHER_PYTHON_INTERPRETERS)
+ CURRENT_RELEASE_ENV = "py36"
"""Should hold currently released py -> for easy updating"""
- QUICKSTART_PY_ENVS = ['py27', 'py34', 'py35', CURRENT_RELEASE_ENV, 'pypy', 'jython']
+ QUICKSTART_PY_ENVS = ["py27", "py34", "py35", CURRENT_RELEASE_ENV, "pypy", "jython"]
"""For choices in tox-quickstart"""
class INFO:
- DEFAULT_CONFIG_NAME = 'tox.ini'
+ DEFAULT_CONFIG_NAME = "tox.ini"
IS_WIN = _sys.platform == "win32"
class PIP:
- SHORT_OPTIONS = ['c', 'e', 'r', 'b', 't', 'd']
+ SHORT_OPTIONS = ["c", "e", "r", "b", "t", "d"]
LONG_OPTIONS = [
- 'build',
- 'cache-dir',
- 'client-cert',
- 'constraint',
- 'download',
- 'editable',
- 'exists-action',
- 'extra-index-url',
- 'global-option',
- 'find-links',
- 'index-url',
- 'install-options',
- 'prefix',
- 'proxy',
- 'no-binary',
- 'only-binary',
- 'requirement',
- 'retries',
- 'root',
- 'src',
- 'target',
- 'timeout',
- 'trusted-host',
- 'upgrade-strategy',
+ "build",
+ "cache-dir",
+ "client-cert",
+ "constraint",
+ "download",
+ "editable",
+ "exists-action",
+ "extra-index-url",
+ "global-option",
+ "find-links",
+ "index-url",
+ "install-options",
+ "prefix",
+ "proxy",
+ "no-binary",
+ "only-binary",
+ "requirement",
+ "retries",
+ "root",
+ "src",
+ "target",
+ "timeout",
+ "trusted-host",
+ "upgrade-strategy",
]
- INSTALL_SHORT_OPTIONS_ARGUMENT = ['-%s' % option for option in SHORT_OPTIONS]
- INSTALL_LONG_OPTIONS_ARGUMENT = ['--%s' % option for option in LONG_OPTIONS]
+ INSTALL_SHORT_OPTIONS_ARGUMENT = ["-{}".format(option) for option in SHORT_OPTIONS]
+ INSTALL_LONG_OPTIONS_ARGUMENT = ["--{}".format(option) for option in LONG_OPTIONS]
diff --git a/tox/exception.py b/tox/exception.py
index aefad5bf..01d0968f 100644
--- a/tox/exception.py
+++ b/tox/exception.py
@@ -14,28 +14,31 @@ def exit_code_str(exception_name, command, exit_code):
Even a normal method failed with "TypeError: descriptor '__getattribute__' requires a
'BaseException' object but received a 'type'".
"""
- str_ = "%s for command %s" % (exception_name, command)
+ str_ = "{} for command {}".format(exception_name, command)
if exit_code is not None:
- str_ += " (exited with code %d)" % (exit_code)
- if (os.name == 'posix') and (exit_code > 128):
- signals = {number: name
- for name, number in vars(signal).items()
- if name.startswith("SIG")}
+ str_ += " (exited with code {:d})".format(exit_code)
+ if (os.name == "posix") and (exit_code > 128):
+ signals = {
+ number: name for name, number in vars(signal).items() if name.startswith("SIG")
+ }
number = exit_code - 128
name = signals.get(number)
if name:
- str_ += ("\nNote: this might indicate a fatal error signal "
- "(%d - 128 = %d: %s)" % (number+128, number, name))
+ str_ += (
+ "\nNote: this might indicate a fatal error signal "
+ "({:d} - 128 = {:d}: {})".format(number + 128, number, name)
+ )
return str_
class Error(Exception):
+
def __str__(self):
- return "%s: %s" % (self.__class__.__name__, self.args[0])
+ return "{}: {}".format(self.__class__.__name__, self.args[0])
class MissingSubstitution(Error):
- FLAG = 'TOX_MISSING_SUBSTITUTION'
+ FLAG = "TOX_MISSING_SUBSTITUTION"
"""placeholder for debugging configurations"""
def __init__(self, name):
@@ -56,6 +59,7 @@ class InterpreterNotFound(Error):
class InvocationError(Error):
"""An error while invoking a script."""
+
def __init__(self, command, exit_code=None):
super(Error, self).__init__(command, exit_code)
self.command = command
diff --git a/tox/interpreters.py b/tox/interpreters.py
index 21967808..c13a5033 100644
--- a/tox/interpreters.py
+++ b/tox/interpreters.py
@@ -10,6 +10,7 @@ import tox
class Interpreters:
+
def __init__(self, hook):
self.name2executable = {}
self.executable2info = {}
@@ -45,11 +46,15 @@ class Interpreters:
return ""
envdir = str(envdir)
try:
- res = exec_on_interpreter(info.executable,
- [inspect.getsource(sitepackagesdir),
- "print(sitepackagesdir(%r))" % envdir])
+ res = exec_on_interpreter(
+ info.executable,
+ [
+ inspect.getsource(sitepackagesdir),
+ "print(sitepackagesdir({!r}))".format(envdir),
+ ],
+ )
except ExecFailed as e:
- print("execution failed: %s -- %s" % (e.out, e.err))
+ print("execution failed: {} -- {}".format(e.out, e.err))
return ""
else:
return res["dir"]
@@ -58,11 +63,9 @@ class Interpreters:
def run_and_get_interpreter_info(name, executable):
assert executable
try:
- result = exec_on_interpreter(executable, [inspect.getsource(pyinfo),
- "print(pyinfo())"])
+ result = exec_on_interpreter(executable, [inspect.getsource(pyinfo), "print(pyinfo())"])
except ExecFailed as e:
- return NoInterpreterInfo(name, executable=e.executable,
- out=e.out, err=e.err)
+ return NoInterpreterInfo(name, executable=e.executable, out=e.out, err=e.err)
else:
return InterpreterInfo(name, executable, **result)
@@ -71,6 +74,7 @@ def exec_on_interpreter(executable, source):
if isinstance(source, list):
source = "\n".join(source)
from subprocess import Popen, PIPE
+
args = [str(executable)]
popen = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE)
popen.stdin.write(source.encode("utf8"))
@@ -80,12 +84,12 @@ def exec_on_interpreter(executable, source):
try:
result = eval(out.strip())
except Exception:
- raise ExecFailed(executable, source, out,
- "could not decode %r" % out)
+ raise ExecFailed(executable, source, out, "could not decode {!r}".format(out))
return result
class ExecFailed(Exception):
+
def __init__(self, executable, source, out, err):
self.executable = executable
self.source = source
@@ -104,15 +108,13 @@ class InterpreterInfo:
self.sysplatform = sysplatform
def __str__(self):
- return "<executable at %s, version_info %s>" % (
- self.executable, self.version_info)
+ return "<executable at {}, version_info {}>".format(self.executable, self.version_info)
class NoInterpreterInfo:
runnable = False
- def __init__(self, name, executable=None,
- out=None, err="not found"):
+ def __init__(self, name, executable=None, out=None, err="not found"):
self.name = name
self.executable = executable
self.version_info = None
@@ -121,17 +123,20 @@ class NoInterpreterInfo:
def __str__(self):
if self.executable:
- return "<executable at %s, not runnable>" % self.executable
+ return "<executable at {}, not runnable>".format(self.executable)
else:
- return "<executable not found for: %s>" % self.name
+ return "<executable not found for: {}>".format(self.name)
if not tox.INFO.IS_WIN:
+
@tox.hookimpl
def tox_get_python_executable(envconfig):
return py.path.local.sysfind(envconfig.basepython)
+
else:
+
@tox.hookimpl
def tox_get_python_executable(envconfig):
name = envconfig.basepython
@@ -143,7 +148,7 @@ else:
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()
+ actual = r"c:\python{}{}\python.exe".format(*m.groups())
if not actual:
actual = win32map.get(name, None)
if actual:
@@ -156,31 +161,28 @@ else:
return locate_via_py(*m.groups())
# Exceptions to the usual windows mapping
- win32map = {
- 'python': sys.executable,
- 'jython': r"c:\jython2.5.1\jython.bat",
- }
+ win32map = {"python": sys.executable, "jython": r"c:\jython2.5.1\jython.bat"}
def locate_via_py(v_maj, v_min):
- ver = "-%s.%s" % (v_maj, v_min)
+ ver = "-{}.{}".format(v_maj, v_min)
script = "import sys; print(sys.executable)"
- py_exe = distutils.spawn.find_executable('py')
+ py_exe = distutils.spawn.find_executable("py")
if py_exe:
proc = subprocess.Popen(
- (py_exe, ver, '-c', script),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ (py_exe, ver, "-c", script), stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
out, _ = proc.communicate()
if not proc.returncode:
- return out.decode('UTF-8').strip()
+ return out.decode("UTF-8").strip()
def pyinfo():
import sys
- return {"version_info": tuple(sys.version_info),
- "sysplatform": sys.platform}
+
+ return {"version_info": tuple(sys.version_info), "sysplatform": sys.platform}
def sitepackagesdir(envdir):
import distutils.sysconfig
+
return {"dir": distutils.sysconfig.get_python_lib(prefix=envdir)}
diff --git a/tox/result.py b/tox/result.py
index e84e85dc..5d23f481 100644
--- a/tox/result.py
+++ b/tox/result.py
@@ -8,6 +8,7 @@ import tox
class ResultLog:
+
def __init__(self, data=None):
if not data:
self.dict = {}
@@ -39,6 +40,7 @@ class ResultLog:
class EnvLog:
+
def __init__(self, reportlog, name, dict):
self.reportlog = reportlog
self.name = name
@@ -46,19 +48,19 @@ 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)")
+ out = pythonexecutable.sysexec(
+ "-c",
+ "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"] = {
- "executable": executable,
- "version_info": version_info,
- "version": version,
+ "executable": executable, "version_info": version_info, "version": version
}
def get_commandlog(self, name):
@@ -69,6 +71,7 @@ class EnvLog:
class CommandLog:
+
def __init__(self, envlog, list):
self.envlog = envlog
self.list = list
diff --git a/tox/session.py b/tox/session.py
index 043c0e5d..e74b81f9 100644
--- a/tox/session.py
+++ b/tox/session.py
@@ -59,24 +59,29 @@ def show_help(config):
tw.write(config._parser._format_help())
tw.line()
tw.line("Environment variables", bold=True)
- tw.line("TOXENV: comma separated list of environments "
- "(overridable by '-e')")
- tw.line("TOX_TESTENV_PASSENV: space-separated list of extra "
- "environment variables to be passed into test command "
- "environments")
+ tw.line("TOXENV: comma separated list of environments (overridable by '-e')")
+ tw.line(
+ "TOX_TESTENV_PASSENV: space-separated list of extra environment variables to be "
+ "passed into test command environments"
+ )
def show_help_ini(config):
tw = py.io.TerminalWriter()
tw.sep("-", "per-testenv attributes")
for env_attr in config._testenv_attr:
- tw.line("%-15s %-8s default: %s" %
- (env_attr.name, "<" + env_attr.type + ">", env_attr.default), bold=True)
+ tw.line(
+ "{:<15} {:<8} default: {}".format(
+ env_attr.name, "<" + env_attr.type + ">", env_attr.default
+ ),
+ bold=True,
+ )
tw.line(env_attr.help)
tw.line()
class Action(object):
+
def __init__(self, session, venv, msg, args):
self.venv = venv
self.msg = msg
@@ -106,12 +111,12 @@ class Action(object):
def setactivity(self, name, msg):
self.activity = name
if msg:
- self.report.verbosity0("%s %s: %s" % (self.venvname, name, msg), bold=True)
+ self.report.verbosity0("{} {}: {}".format(self.venvname, name, msg), bold=True)
else:
- self.report.verbosity1("%s %s: %s" % (self.venvname, name, msg), bold=True)
+ self.report.verbosity1("{} {}: {}".format(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("{} {}: {}".format(self.venvname, name, msg), bold=True)
def _initlogpath(self, actionid):
if self.venv:
@@ -119,12 +124,12 @@ class Action(object):
else:
logdir = self.session.config.logdir
try:
- log_count = len(logdir.listdir("%s-*" % actionid))
+ log_count = len(logdir.listdir("{}-*".format(actionid)))
except (py.error.ENOENT, py.error.ENOTDIR):
logdir.ensure(dir=1)
log_count = 0
- path = logdir.join("%s-%s.log" % (actionid, log_count))
- f = path.open('w')
+ path = logdir.join("{}-{}.log".format(actionid, log_count))
+ f = path.open("w")
f.flush()
return f
@@ -133,10 +138,10 @@ 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\n\n" % (self.id, self.msg, args))
+ fout.write("actionid: {}\nmsg: {}\ncmdargs: {!r}\n\n".format(self.id, self.msg, args))
fout.flush()
outpath = py.path.local(fout.name)
- fin = outpath.open('rb')
+ fin = outpath.open("rb")
fin.read() # read the header, so it won't be written to stdout
stdout = fout
elif returnout:
@@ -145,11 +150,11 @@ class Action(object):
# FIXME XXX cwd = self.session.config.cwd
cwd = py.path.local()
try:
- popen = self._popen(args, cwd, env=env,
- stdout=stdout, stderr=subprocess.STDOUT)
+ popen = self._popen(args, cwd, env=env, stdout=stdout, stderr=subprocess.STDOUT)
except OSError as e:
- self.report.error("invocation failed (errno %d), args: %s, cwd: %s" %
- (e.errno, args, cwd))
+ self.report.error(
+ "invocation failed (errno {:d}), args: {}, cwd: {}".format(e.errno, args, cwd)
+ )
raise
popen.outpath = outpath
popen.args = [str(x) for x in args]
@@ -165,7 +170,7 @@ class Action(object):
raise ValueError("stderr must not be piped here")
# we read binary from the process and must write using a
# binary stream
- buf = getattr(sys.stdout, 'buffer', sys.stdout)
+ buf = getattr(sys.stdout, "buffer", sys.stdout)
out = None
last_time = time.time()
while 1:
@@ -174,7 +179,7 @@ class Action(object):
data = fin.read(1)
if data:
buf.write(data)
- if b'\n' in data or (time.time() - last_time) > 1:
+ if b"\n" in data or (time.time() - last_time) > 1:
# we flush on newlines or after 1 second to
# provide quick enough feedback to the user
# when printing a dot per test
@@ -201,16 +206,16 @@ class Action(object):
if ret and not ignore_ret:
invoked = " ".join(map(str, popen.args))
if outpath:
- self.report.error("invocation failed (exit code %d), logfile: %s" %
- (ret, outpath))
+ self.report.error(
+ "invocation failed (exit code {:d}), logfile: {}".format(ret, outpath)
+ )
out = outpath.read()
self.report.error(out)
if hasattr(self, "commandlog"):
self.commandlog.add_command(popen.args, out, ret)
- raise tox.exception.InvocationError(
- "%s (see %s)" % (invoked, outpath), ret)
+ raise tox.exception.InvocationError("{} (see {})".format(invoked, outpath), ret)
else:
- raise tox.exception.InvocationError("%r" % (invoked,), ret)
+ raise tox.exception.InvocationError("{!r}".format(invoked), ret)
if not out and outpath:
out = outpath.read()
if hasattr(self, "commandlog"):
@@ -226,15 +231,22 @@ class Action(object):
# subprocess does not always take kindly to .py scripts so adding the interpreter here
if tox.INFO.IS_WIN:
ext = os.path.splitext(str(newargs[0]))[1].lower()
- if ext == '.py' and self.venv:
+ if ext == ".py" and self.venv:
newargs = [str(self.venv.envconfig.envpython)] + newargs
return newargs
def _popen(self, args, cwd, stdout, stderr, env=None):
if env is None:
env = os.environ.copy()
- return self.session.popen(self._rewriteargs(cwd, args), shell=False, cwd=str(cwd),
- universal_newlines=True, stdout=stdout, stderr=stderr, env=env)
+ return self.session.popen(
+ self._rewriteargs(cwd, args),
+ shell=False,
+ cwd=str(cwd),
+ universal_newlines=True,
+ stdout=stdout,
+ stderr=stderr,
+ env=env,
+ )
class Verbosity(object):
@@ -256,8 +268,9 @@ class Reporter(object):
@property
def verbosity(self):
if self.session:
- return (self.session.config.option.verbose_level -
- self.session.config.option.quiet_level)
+ return (
+ self.session.config.option.verbose_level - self.session.config.option.quiet_level
+ )
else:
return Verbosity.DEBUG
@@ -265,21 +278,23 @@ class Reporter(object):
""" 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(" {}$ {} >{}".format(popen.cwd, cmd, popen.outpath))
else:
- self.verbosity1(" %s$ %s " % (popen.cwd, cmd))
+ self.verbosity1(" {}$ {} ".format(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)
+ msg = "{} {}".format(action.msg, " ".join(map(str, action.args)))
+ self.verbosity2("{} start: {}".format(action.venvname, msg), bold=True)
assert not hasattr(action, "_starttime")
action._starttime = time.time()
def logaction_finish(self, action):
duration = time.time() - action._starttime
- self.verbosity2("%s finish: %s after %.2f seconds" % (
- action.venvname, action.msg, duration), bold=True)
- delattr(action, '_starttime')
+ self.verbosity2(
+ "{} finish: {} after {:.2f} seconds".format(action.venvname, action.msg, duration),
+ bold=True,
+ )
+ delattr(action, "_starttime")
def startsummary(self):
if self.verbosity >= Verbosity.QUIET:
@@ -291,7 +306,7 @@ class Reporter(object):
def using(self, msg):
if self.verbosity >= 1:
- self.logline("using %s" % (msg,), bold=True)
+ self.logline("using {}".format(msg), bold=True)
def keyboard_interrupt(self):
self.error("KEYBOARDINTERRUPT")
@@ -312,31 +327,31 @@ class Reporter(object):
def warning(self, msg):
if self.verbosity >= Verbosity.QUIET:
- self.logline("WARNING:" + msg, red=True)
+ self.logline("WARNING: {}".format(msg), red=True)
def error(self, msg):
if self.verbosity >= Verbosity.QUIET:
- self.logline("ERROR: " + msg, red=True)
+ self.logline("ERROR: {}".format(msg), red=True)
def skip(self, msg):
if self.verbosity >= Verbosity.QUIET:
- self.logline("SKIPPED:" + msg, yellow=True)
+ self.logline("SKIPPED: {}".format(msg), yellow=True)
def logline(self, msg, **opts):
self._reportedlines.append(msg)
- self.tw.line("%s" % msg, **opts)
+ self.tw.line("{}".format(msg), **opts)
def verbosity0(self, msg, **opts):
if self.verbosity >= Verbosity.DEFAULT:
- self.logline("%s" % msg, **opts)
+ self.logline("{}".format(msg), **opts)
def verbosity1(self, msg, **opts):
if self.verbosity >= Verbosity.INFO:
- self.logline("%s" % msg, **opts)
+ self.logline("{}".format(msg), **opts)
def verbosity2(self, msg, **opts):
if self.verbosity >= Verbosity.DEBUG:
- self.logline("%s" % msg, **opts)
+ self.logline("{}".format(msg), **opts)
# def log(self, msg):
# print(msg, file=sys.stderr)
@@ -352,14 +367,11 @@ class Session:
self.report = Report(self)
self.make_emptydir(config.logdir)
config.logdir.ensure(dir=1)
- self.report.using("tox.ini: %s" % (self.config.toxinipath,))
+ self.report.using("tox.ini: {}".format(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)
except tox.exception.ConfigError as e:
@@ -374,12 +386,13 @@ class Session:
def _makevenv(self, name):
envconfig = self.config.envconfigs.get(name, None)
if envconfig is None:
- self.report.error("unknown environment %r" % name)
+ self.report.error("unknown environment {!r}".format(name))
raise LookupError(name)
elif envconfig.envdir == self.config.toxinidir:
self.report.error(
- "venv %r in %s would delete project" % (name, envconfig.envdir))
- raise tox.exception.ConfigError('envdir must not equal toxinidir')
+ "venv {!r} in {} would delete project".format(name, envconfig.envdir)
+ )
+ raise tox.exception.ConfigError("envdir must not equal toxinidir")
venv = VirtualEnv(envconfig=envconfig, session=self)
self._name2venv[name] = venv
return venv
@@ -397,7 +410,7 @@ class Session:
return action
def runcommand(self):
- self.report.using("tox-%s from %s" % (tox.__version__, tox.__file__))
+ self.report.using("tox-{} from {}".format(tox.__version__, tox.__file__))
verbosity = (self.report.verbosity > Verbosity.DEFAULT)
if self.config.option.showconfig:
self.showconfig()
@@ -412,7 +425,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: {}".format(src))
raise SystemExit(1)
target = destdir.join(relpath)
target.dirpath().ensure(dir=1)
@@ -423,22 +436,30 @@ class Session:
if not setup.check():
self.report.error(
"No setup.py file found. The expected location is:\n"
- " %s\n"
+ " {}\n"
"You can\n"
" 1. Create one:\n"
" https://packaging.python.org/tutorials/distributing-packages/#setup-py\n"
" 2. Configure tox to avoid running sdist:\n"
" http://tox.readthedocs.io/en/latest/example/general.html"
- "#avoiding-expensive-sdist" % setup
+ "#avoiding-expensive-sdist".format(setup)
)
raise SystemExit(1)
action = self.newaction(None, "packaging")
with action:
action.setactivity("sdist-make", setup)
self.make_emptydir(self.config.distdir)
- action.popen([sys.executable, setup, "sdist", "--formats=zip",
- "--dist-dir", self.config.distdir, ],
- cwd=self.config.setupdir)
+ action.popen(
+ [
+ sys.executable,
+ setup,
+ "sdist",
+ "--formats=zip",
+ "--dist-dir",
+ self.config.distdir,
+ ],
+ cwd=self.config.setupdir,
+ )
try:
return self.config.distdir.listdir()[0]
except py.error.ENOENT:
@@ -446,32 +467,32 @@ class Session:
data = []
with open(str(setup)) as fp:
for line in fp:
- if line and line[0] == '#':
+ if line and line[0] == "#":
continue
data.append(line)
- if not ''.join(data).strip():
- self.report.error(
- 'setup.py is empty'
- )
+ if not "".join(data).strip():
+ self.report.error("setup.py is empty")
raise SystemExit(1)
self.report.error(
- 'No dist directory found. Please check setup.py, e.g with:\n'
- ' python setup.py sdist'
+ "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)
+ self.report.info(" removing {}".format(path))
shutil.rmtree(str(path), ignore_errors=True)
path.ensure(dir=1)
def setupenv(self, venv):
if venv.envconfig.missing_subs:
venv.status = (
- "unresolvable substitution(s): %s. "
- "Environment variables are missing or defined recursively." %
- (','.join(["'%s'" % m for m in venv.envconfig.missing_subs])))
+ "unresolvable substitution(s): {}. "
+ "Environment variables are missing or defined recursively.".format(
+ ",".join(["'{}'".format(m) for m in venv.envconfig.missing_subs])
+ )
+ )
return
if not venv.matching_platform():
venv.status = "platform mismatch"
@@ -487,25 +508,28 @@ class Session:
if e.args[0] != 2:
raise
status = (
- "Error creating virtualenv. Note that spaces in paths are "
- "not supported by virtualenv. Error details: %r" % e)
+ "Error creating virtualenv. Note that spaces in paths are "
+ "not supported by virtualenv. Error details: {!r}".format(e)
+ )
except tox.exception.InvocationError as e:
status = (
- "Error creating virtualenv. Note that some special "
- "characters (e.g. ':' and unicode symbols) in paths are "
- "not supported by virtualenv. Error details: %r" % e)
+ "Error creating virtualenv. Note that some special characters (e.g. ':' and "
+ "unicode symbols) in paths are not supported by virtualenv. Error details: "
+ "{!r}".format(e)
+ )
except tox.exception.InterpreterNotFound as e:
status = e
if self.config.option.skip_missing_interpreters:
default_ret_code = 0
if status:
+ str_status = str(status)
commandlog = envlog.get_commandlog("setup")
- commandlog.add_command(["setup virtualenv"], str(status), default_ret_code)
+ commandlog.add_command(["setup virtualenv"], str_status, default_ret_code)
venv.status = status
if default_ret_code == 0:
- self.report.skip(str(status))
+ self.report.skip(str_status)
else:
- self.report.error(str(status))
+ self.report.error(str_status)
return False
commandpath = venv.getcommandpath("python")
envlog.set_python_info(commandpath)
@@ -550,31 +574,31 @@ class Session:
:return: Path to the distribution
:rtype: py.path.local
"""
- if not self.config.option.sdistonly and (self.config.sdistsrc or
- self.config.option.installpkg):
+ if (
+ not self.config.option.sdistonly
+ and (self.config.sdistsrc or self.config.option.installpkg)
+ ):
path = self.config.option.installpkg
if not path:
path = self.config.sdistsrc
path = self._resolve_pkg(path)
- self.report.info("using package %r, skipping 'sdist' activity " %
- str(path))
+ self.report.info("using package {!r}, skipping 'sdist' activity ".format(str(path)))
else:
try:
path = self._makesdist()
except tox.exception.InvocationError:
v = sys.exc_info()[1]
- self.report.error("FAIL could not package project - v = %r" %
- v)
+ self.report.error("FAIL could not package project - v = {!r}".format(v))
return
sdistfile = self.config.distshare.join(path.basename)
if sdistfile != path:
- self.report.info("copying new sdistfile to %r" %
- str(sdistfile))
+ self.report.info("copying new sdistfile to {!r}".format(str(sdistfile)))
try:
sdistfile.dirpath().ensure(dir=1)
except py.error.Error:
- self.report.warning("could not copy distfile to %s" %
- sdistfile.dirpath())
+ self.report.warning(
+ "could not copy distfile to {}".format(sdistfile.dirpath())
+ )
else:
path.copy(sdistfile)
return path
@@ -634,26 +658,26 @@ 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 = " {}: {}".format(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 = " {}: {}".format(venv.envconfig.envname, str(status))
self.report.skip(msg)
elif status and status == "ignored failed command":
- msg = " %s: %s" % (venv.envconfig.envname, str(status))
+ msg = " {}: {}".format(venv.envconfig.envname, str(status))
self.report.good(msg)
elif status and status != "skipped tests":
- msg = " %s: %s" % (venv.envconfig.envname, str(status))
+ msg = " {}: {}".format(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(" {}: {}".format(venv.envconfig.envname, status))
if not retcode:
self.report.good(" congratulations :)")
@@ -661,7 +685,7 @@ class Session:
if path:
path = py.path.local(path)
path.write(self.resultlog.dumps_json())
- self.report.line("wrote json report at: %s" % path)
+ self.report.line("wrote json report at: {}".format(path))
return retcode
def showconfig(self):
@@ -675,23 +699,22 @@ class Session:
self.report.keyvalue("skipsdist: ", self.config.skipsdist)
self.report.tw.line()
for envconfig in self.config.envconfigs.values():
- self.report.line("[testenv:%s]" % envconfig.envname, bold=True)
+ self.report.line("[testenv:{}]".format(envconfig.envname), bold=True)
for attr in self.config._parser._testenv_attr:
- self.report.line(" %-15s = %s"
- % (attr.name, getattr(envconfig, attr.name)))
+ self.report.line(" {:<15} = {}".format(attr.name, getattr(envconfig, attr.name)))
def showenvs(self, all_envs=False, description=False):
env_conf = self.config.envconfigs # this contains all environments
default = self.config.envlist # this only the defaults
extra = sorted(e for e in env_conf if e not in default) if all_envs else []
if description:
- self.report.line('default environments:')
+ self.report.line("default environments:")
max_length = max(len(env) for env in (default + extra))
def report_env(e):
if description:
- text = env_conf[e].description or '[no description]'
- msg = '{} -> {}'.format(e.ljust(max_length), text).strip()
+ text = env_conf[e].description or "[no description]"
+ msg = "{} -> {}".format(e.ljust(max_length), text).strip()
else:
msg = e
self.report.line(msg)
@@ -700,19 +723,18 @@ class Session:
report_env(e)
if all_envs and extra:
if description:
- self.report.line('')
- self.report.line('additional environments:')
+ self.report.line("")
+ self.report.line("additional environments:")
for e in extra:
report_env(e)
def info_versions(self):
- versions = ['tox-%s' % tox.__version__]
+ versions = ["tox-{}".format(tox.__version__)]
proc = subprocess.Popen(
- (sys.executable, '-m', 'virtualenv', '--version'),
- stdout=subprocess.PIPE,
+ (sys.executable, "-m", "virtualenv", "--version"), stdout=subprocess.PIPE
)
out, _ = proc.communicate()
- versions.append('virtualenv-{}'.format(out.decode('UTF-8').strip()))
+ versions.append("virtualenv-{}".format(out.decode("UTF-8").strip()))
self.report.keyvalue("tool-versions:", " ".join(versions))
def _resolve_pkg(self, pkgspec):
@@ -730,7 +752,7 @@ class Session:
return p
if not p.dirpath().check(dir=1):
raise tox.exception.MissingDirectory(p.dirpath())
- self.report.info("determining %s" % p)
+ self.report.info("determining {}".format(p))
candidates = p.dirpath().listdir(p.basename)
if len(candidates) == 0:
raise tox.exception.MissingDependency(pkgspec)
@@ -741,8 +763,7 @@ class Session:
if ver is not None:
items.append((ver, x))
else:
- self.report.warning("could not determine version of: %s" %
- str(x))
+ self.report.warning("could not determine version of: {}".format(str(x)))
items.sort()
if not items:
raise tox.exception.MissingDependency(pkgspec)
diff --git a/tox/venv.py b/tox/venv.py
index 1f05c3a1..35b5d4a1 100755
--- a/tox/venv.py
+++ b/tox/venv.py
@@ -11,8 +11,8 @@ from .config import DepConfig
class CreationConfig:
- def __init__(self, md5, python, version, sitepackages,
- usedevelop, deps, alwayscopy):
+
+ def __init__(self, md5, python, version, sitepackages, usedevelop, deps, alwayscopy):
self.md5 = md5
self.python = python
self.version = version
@@ -22,11 +22,14 @@ class CreationConfig:
self.deps = deps
def writeconfig(self, path):
- lines = ["%s %s" % (self.md5, self.python)]
- lines.append("%s %d %d %d" % (self.version, self.sitepackages,
- self.usedevelop, self.alwayscopy))
+ lines = [
+ "{} {}".format(self.md5, self.python),
+ "{} {:d} {:d} {:d}".format(
+ self.version, self.sitepackages, self.usedevelop, self.alwayscopy
+ ),
+ ]
for dep in self.deps:
- lines.append("%s %s" % dep)
+ lines.append("{} {}".format(*dep))
path.ensure()
path.write("\n".join(lines))
@@ -49,16 +52,20 @@ class CreationConfig:
return None
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.usedevelop == other.usedevelop and
- self.alwayscopy == other.alwayscopy and
- self.deps == other.deps)
+ return (
+ other
+ and self.md5 == other.md5
+ and self.python == other.python
+ and self.version == other.version
+ and self.sitepackages == other.sitepackages
+ and self.usedevelop == other.usedevelop
+ and self.alwayscopy == other.alwayscopy
+ and self.deps == other.deps
+ )
class VirtualEnv(object):
+
def __init__(self, envconfig=None, session=None):
self.envconfig = envconfig
self.session = session
@@ -82,7 +89,7 @@ class VirtualEnv(object):
return self.envconfig.envname
def __repr__(self):
- return "<VirtualEnv at %r>" % (self.path)
+ return "<VirtualEnv at {!r}>".format(self.path)
def getcommandpath(self, name, venv=True, cwd=None):
""" Return absolute path (str or localpath) for specified command name.
@@ -105,8 +112,7 @@ class VirtualEnv(object):
path = self._normal_lookup(name)
if path is None:
- raise tox.exception.InvocationError(
- "could not find executable %r" % (name,))
+ raise tox.exception.InvocationError("could not find executable {!r}".format(name))
return str(path) # will not be rewritten for reporting
@@ -128,19 +134,18 @@ class VirtualEnv(object):
if not self.is_allowed_external(path):
self.session.report.warning(
"test command found but not installed in testenv\n"
- " cmd: %s\n"
- " env: %s\n"
+ " cmd: {}\n"
+ " env: {}\n"
"Maybe you forgot to specify a dependency? "
- "See also the whitelist_externals envconfig setting." % (
- path, self.envconfig.envdir))
+ "See also the whitelist_externals envconfig setting.".format(
+ path, self.envconfig.envdir
+ )
+ )
def is_allowed_external(self, p):
tryadd = [""]
if tox.INFO.IS_WIN:
- 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:
@@ -153,8 +158,7 @@ class VirtualEnv(object):
if status string is empty, all is ok.
"""
rconfig = CreationConfig.readconfig(self.path_config)
- if not self.envconfig.recreate and rconfig and \
- rconfig.matches(self._getliveconfig()):
+ if not self.envconfig.recreate and rconfig and rconfig.matches(self._getliveconfig()):
action.info("reusing", self.envconfig.envdir)
return
if rconfig is None:
@@ -170,8 +174,7 @@ class VirtualEnv(object):
self.hook.tox_testenv_install_deps(action=action, venv=self)
except tox.exception.InvocationError:
v = sys.exc_info()[1]
- return "could not install deps %s; v = %r" % (
- self.envconfig.deps, v)
+ return "could not install deps {}; v = {!r}".format(self.envconfig.deps, v)
def _getliveconfig(self):
python = self.envconfig.python_info.executable
@@ -185,8 +188,7 @@ class VirtualEnv(object):
raw_dep = dep.name
md5 = getdigest(raw_dep)
deps.append((md5, raw_dep))
- return CreationConfig(md5, python, version,
- sitepackages, develop, deps, alwayscopy)
+ return CreationConfig(md5, python, version, sitepackages, develop, deps, alwayscopy)
def _getresolvedeps(self):
deps = []
@@ -208,20 +210,19 @@ class VirtualEnv(object):
self._getliveconfig().writeconfig(self.path_config)
def _needs_reinstall(self, setupdir, action):
- setup_py = setupdir.join('setup.py')
- setup_cfg = setupdir.join('setup.cfg')
- args = [self.envconfig.envpython, str(setup_py), '--name']
+ setup_py = setupdir.join("setup.py")
+ setup_cfg = setupdir.join("setup.cfg")
+ args = [self.envconfig.envpython, str(setup_py), "--name"]
env = self._getenv()
- output = action.popen(args, cwd=setupdir, redirect=False,
- returnout=True, env=env)
+ output = action.popen(args, cwd=setupdir, redirect=False, returnout=True, env=env)
name = output.strip()
- args = [self.envconfig.envpython, '-c', 'import sys; print(sys.path)']
+ args = [self.envconfig.envpython, "-c", "import sys; print(sys.path)"]
out = action.popen(args, redirect=False, returnout=True, env=env)
try:
sys_path = ast.literal_eval(out.strip())
except SyntaxError:
sys_path = []
- egg_info_fname = '.'.join((name, 'egg-info'))
+ egg_info_fname = ".".join((name, "egg-info"))
for d in reversed(sys_path):
egg_info = py.path.local(d).join(egg_info_fname)
if egg_info.check():
@@ -235,7 +236,7 @@ class VirtualEnv(object):
def developpkg(self, setupdir, action):
assert action is not None
- if getattr(self, 'just_created', False):
+ if getattr(self, "just_created", False):
action.setactivity("develop-inst", setupdir)
self.finish()
extraopts = []
@@ -244,25 +245,25 @@ class VirtualEnv(object):
action.setactivity("develop-inst-noop", setupdir)
return
action.setactivity("develop-inst-nodeps", setupdir)
- extraopts = ['--no-deps']
+ extraopts = ["--no-deps"]
if action.venv.envconfig.extras:
- setupdir += '[%s]' % ','.join(action.venv.envconfig.extras)
+ setupdir += "[{}]".format(",".join(action.venv.envconfig.extras))
- self._install(['-e', setupdir], extraopts=extraopts, action=action)
+ self._install(["-e", setupdir], extraopts=extraopts, action=action)
def installpkg(self, sdistpath, action):
assert action is not None
- if getattr(self, 'just_created', False):
+ if getattr(self, "just_created", False):
action.setactivity("inst", sdistpath)
self.finish()
extraopts = []
else:
action.setactivity("inst-nodeps", sdistpath)
- extraopts = ['-U', '--no-deps']
+ extraopts = ["-U", "--no-deps"]
if action.venv.envconfig.extras:
- sdistpath += '[%s]' % ','.join(action.venv.envconfig.extras)
+ sdistpath += "[{}]".format(",".join(action.venv.envconfig.extras))
self._install([sdistpath], extraopts=extraopts, action=action)
@@ -276,30 +277,33 @@ class VirtualEnv(object):
def run_install_command(self, packages, action, options=()):
argv = self.envconfig.install_command[:]
- i = argv.index('{packages}')
+ i = argv.index("{packages}")
argv[i:i + 1] = packages
- if '{opts}' in argv:
- i = argv.index('{opts}')
+ if "{opts}" in argv:
+ i = argv.index("{opts}")
argv[i:i + 1] = list(options)
- for x in ('PIP_RESPECT_VIRTUALENV', 'PIP_REQUIRE_VIRTUALENV',
- '__PYVENV_LAUNCHER__'):
+ for x in ("PIP_RESPECT_VIRTUALENV", "PIP_REQUIRE_VIRTUALENV", "__PYVENV_LAUNCHER__"):
os.environ.pop(x, None)
- if 'PYTHONPATH' not in self.envconfig.passenv:
+ if "PYTHONPATH" not in self.envconfig.passenv:
# If PYTHONPATH not explicitly asked for, remove it.
- if 'PYTHONPATH' in os.environ:
+ if "PYTHONPATH" in os.environ:
self.session.report.warning(
"Discarding $PYTHONPATH from environment, to override "
"specify PYTHONPATH in 'passenv' in your configuration."
)
- os.environ.pop('PYTHONPATH')
+ os.environ.pop("PYTHONPATH")
old_stdout = sys.stdout
- sys.stdout = codecs.getwriter('utf8')(sys.stdout)
+ sys.stdout = codecs.getwriter("utf8")(sys.stdout)
try:
- self._pcall(argv, cwd=self.envconfig.config.toxinidir,
- action=action, redirect=self.session.report.verbosity < 2)
+ self._pcall(
+ argv,
+ cwd=self.envconfig.config.toxinidir,
+ action=action,
+ redirect=self.session.report.verbosity < 2,
+ )
finally:
sys.stdout = old_stdout
@@ -313,7 +317,7 @@ class VirtualEnv(object):
dep = DepConfig(str(dep), None)
assert isinstance(dep, DepConfig), dep
if dep.indexserver is None:
- ixserver = self.envconfig.config.indexserver['default']
+ ixserver = self.envconfig.config.indexserver["default"]
else:
ixserver = dep.indexserver
d.setdefault(ixserver, []).append(dep.name)
@@ -326,8 +330,7 @@ class VirtualEnv(object):
options = self._installopts(ixserver.url)
if extraopts:
options.extend(extraopts)
- self.run_install_command(packages=packages, options=options,
- action=action)
+ self.run_install_command(packages=packages, options=options, action=action)
def _getenv(self, testcommand=False):
if testcommand:
@@ -344,7 +347,7 @@ class VirtualEnv(object):
# in any case we honor per-testenv setenv configuration
env.update(self.envconfig.setenv)
- env['VIRTUAL_ENV'] = str(self.path)
+ env["VIRTUAL_ENV"] = str(self.path)
return env
def test(self, redirect=False):
@@ -356,12 +359,11 @@ class VirtualEnv(object):
cwd = self.envconfig.changedir
env = self._getenv(testcommand=True)
# Display PYTHONHASHSEED to assist with reproducibility.
- action.setactivity("runtests", "PYTHONHASHSEED=%r" % env.get('PYTHONHASHSEED'))
+ action.setactivity("runtests", "PYTHONHASHSEED={!r}".format(env.get("PYTHONHASHSEED")))
for i, argv in enumerate(self.envconfig.commands):
# have to make strings as _pcall changes argv[0] to a local()
# happens if the same environment is invoked twice
- message = "commands[%s] | %s" % (i, ' '.join(
- [str(x) for x in argv]))
+ message = "commands[{}] | {}".format(i, " ".join([str(x) for x in argv]))
action.setactivity("runtests", message)
# check to see if we need to ignore the return code
# if so, we need to alter the command line arguments
@@ -375,13 +377,18 @@ class VirtualEnv(object):
ignore_ret = False
try:
- self._pcall(argv, cwd=cwd, action=action, redirect=redirect,
- ignore_ret=ignore_ret, testcommand=True)
+ self._pcall(
+ argv,
+ cwd=cwd,
+ action=action,
+ redirect=redirect,
+ ignore_ret=ignore_ret,
+ testcommand=True,
+ )
except tox.exception.InvocationError as err:
if self.envconfig.ignore_outcome:
- self.session.report.warning(
- "command failed but result from testenv is ignored\n"
- " cmd: %s" % (str(err),))
+ msg = "command failed but result from testenv is ignored\ncmd:"
+ self.session.report.warning("{} {}".format(msg, err))
self.status = "ignored failed command"
continue # keep processing commands
@@ -394,20 +401,20 @@ class VirtualEnv(object):
self.session.report.error(self.status)
raise
- def _pcall(self, args, cwd, venv=True, testcommand=False,
- action=None, redirect=True, ignore_ret=False):
- os.environ.pop('VIRTUALENV_PYTHON', None)
+ def _pcall(
+ self, args, cwd, venv=True, testcommand=False, action=None, redirect=True, ignore_ret=False
+ ):
+ os.environ.pop("VIRTUALENV_PYTHON", None)
cwd.ensure(dir=1)
args[0] = self.getcommandpath(args[0], venv, cwd)
- if sys.platform != 'win32' and 'TOX_LIMITED_SHEBANG' in os.environ:
+ if sys.platform != "win32" and "TOX_LIMITED_SHEBANG" in os.environ:
args = prepend_shebang_interpreter(args)
env = self._getenv(testcommand=testcommand)
bindir = str(self.envconfig.envbindir)
- env['PATH'] = p = os.pathsep.join([bindir, os.environ["PATH"]])
- self.session.report.verbosity2("setting PATH=%s" % p)
- return action.popen(args, cwd=cwd, env=env,
- redirect=redirect, ignore_ret=ignore_ret)
+ env["PATH"] = p = os.pathsep.join([bindir, os.environ["PATH"]])
+ self.session.report.verbosity2("setting PATH={}".format(p))
+ return action.popen(args, cwd=cwd, env=env, redirect=redirect, ignore_ret=ignore_ret)
def getdigest(path):
@@ -430,8 +437,8 @@ def prepend_shebang_interpreter(args):
# a maximum size of 2048 bytes to limit excessive reading and support UNIX
# systems which may support a longer interpret length.
try:
- with open(args[0], 'rb') as f:
- if f.read(1) == b'#' and f.read(1) == b'!':
+ with open(args[0], "rb") as f:
+ if f.read(1) == b"#" and f.read(1) == b"!":
MAXINTERP = 2048
interp = f.readline(MAXINTERP).rstrip()
interp_args = interp.split(None, 1)[:2]
@@ -444,13 +451,13 @@ def prepend_shebang_interpreter(args):
@tox.hookimpl
def tox_testenv_create(venv, action):
config_interpreter = venv.getsupportedinterpreter()
- args = [sys.executable, '-m', 'virtualenv']
+ args = [sys.executable, "-m", "virtualenv"]
if venv.envconfig.sitepackages:
- args.append('--system-site-packages')
+ args.append("--system-site-packages")
if venv.envconfig.alwayscopy:
- args.append('--always-copy')
+ args.append("--always-copy")
# add interpreter explicitly, to prevent using default (virtualenv.ini)
- args.extend(['--python', str(config_interpreter)])
+ args.extend(["--python", str(config_interpreter)])
venv.session.make_emptydir(venv.path)
basepath = venv.path.dirpath()
basepath.ensure(dir=1)
@@ -464,7 +471,7 @@ def tox_testenv_install_deps(venv, action):
deps = venv._getresolvedeps()
if deps:
depinfo = ", ".join(map(str, deps))
- action.setactivity("installdeps", "%s" % depinfo)
+ action.setactivity("installdeps", depinfo)
venv._install(deps, action=action)
return True # Return non-None to indicate plugin has completed
@@ -479,9 +486,7 @@ def tox_runtest(venv, redirect):
def tox_runenvreport(venv, action):
# write out version dependency information
args = venv.envconfig.list_dependencies_command
- output = venv._pcall(args,
- cwd=venv.envconfig.config.toxinidir,
- action=action)
+ output = venv._pcall(args, cwd=venv.envconfig.config.toxinidir, action=action)
# the output contains a mime-header, skip it
output = output.split("\n\n")[-1]
packages = output.strip().split("\n")