Skip to content

Commit

Permalink
Un-hardcode the supported factors again
Browse files Browse the repository at this point in the history
  • Loading branch information
asottile committed Jul 25, 2019
1 parent 1e6430c commit 84c4c8d
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 80 deletions.
2 changes: 1 addition & 1 deletion src/tox/_pytestplugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ def build_session(config):
def current_tox_py():
"""generate the current (test runners) python versions key
e.g. py37 when running under Python 3.7"""
return "py{}".format("".join(str(i) for i in sys.version_info[0:2]))
return "py{}{}".format(*sys.version_info)


def pytest_runtest_setup(item):
Expand Down
48 changes: 26 additions & 22 deletions src/tox/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@
Import hookimpl directly from tox instead.
"""

default_factors = tox.PYTHON.DEFAULT_FACTORS
"""DEPRECATED MOVE - please update to new location."""

WITHIN_PROVISION = os.environ.get(str("TOX_PROVISION")) == "1"


Expand Down Expand Up @@ -549,35 +546,42 @@ def basepython_default(testenv_config, value):
python conflict is set in which case the factor name implied version if forced
"""
for factor in testenv_config.factors:
if factor in tox.PYTHON.DEFAULT_FACTORS:
implied_python = tox.PYTHON.DEFAULT_FACTORS[factor]
match = tox.PYTHON.PY_FACTORS_RE.match(factor)
if match:
base_exe = {"py": "python"}.get(match.group(1), match.group(1))
version_s = match.group(2)
if not version_s:
version_info = ()
elif len(version_s) == 1:
version_info = (version_s,)
else:
version_info = (version_s[0], version_s[1:])
implied_version = ".".join(version_info)
implied_python = "{}{}".format(base_exe, implied_version)
break
else:
implied_python, factor = None, None
implied_python, version_info, implied_version = None, (), ""

if testenv_config.config.ignore_basepython_conflict and implied_python is not None:
return implied_python

proposed_python = (implied_python or sys.executable) if value is None else str(value)
if implied_python is not None and implied_python != proposed_python:
testenv_config.basepython = proposed_python
match = tox.PYTHON.PY_FACTORS_RE.match(factor)
implied_version = match.group(2) if match else None
if implied_version is not None:
python_info_for_proposed = testenv_config.python_info
if not isinstance(python_info_for_proposed, NoInterpreterInfo):
proposed_version = "".join(
str(i) for i in python_info_for_proposed.version_info[0:2]
)
# '27'.startswith('2') or '27'.startswith('27')
if not proposed_version.startswith(implied_version):
# TODO(stephenfin): Raise an exception here in tox 4.0
warnings.warn(
"conflicting basepython version (set {}, should be {}) for env '{}';"
"resolve conflict or set ignore_basepython_conflict".format(
proposed_version, implied_version, testenv_config.envname
)
python_info_for_proposed = testenv_config.python_info
if not isinstance(python_info_for_proposed, NoInterpreterInfo):
proposed_version = ".".join(
str(x) for x in python_info_for_proposed.version_info[: len(version_info)]
)
if proposed_version != implied_version:
# TODO(stephenfin): Raise an exception here in tox 4.0
warnings.warn(
"conflicting basepython version (set {}, should be {}) for env '{}';"
"resolve conflict or set ignore_basepython_conflict".format(
proposed_version, implied_version, testenv_config.envname
)
)

return proposed_python

parser.add_testenv_attribute(
Expand Down
31 changes: 3 additions & 28 deletions src/tox/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,11 @@
_THIS_FILE = os.path.realpath(os.path.abspath(__file__))


def _construct_default_factors(cpython_versions, pypy_versions, 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 cpython_versions
}
)
default_factors.update({exc: exc for exc in ["pypy", "pypy2", "pypy3"]})
default_factors.update(
{
"pypy{}{}".format(major, minor): "pypy{}.{}".format(major, minor)
for major, minor in pypy_versions
}
)
default_factors.update({interpreter: interpreter for interpreter in other_interpreters})
return default_factors


class PYTHON:
PY_FACTORS_RE = re.compile("^(?!py$)(py|pypy|jython)([2-9][0-9]?)?$")
CPYTHON_VERSION_TUPLES = [(2, 7), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8)]
PYPY_VERSION_TUPLES = [(2, 7), (3, 5)]
OTHER_PYTHON_INTERPRETERS = ["jython"]
DEFAULT_FACTORS = _construct_default_factors(
CPYTHON_VERSION_TUPLES, PYPY_VERSION_TUPLES, OTHER_PYTHON_INTERPRETERS
)
CURRENT_RELEASE_ENV = "py36"
PY_FACTORS_RE = re.compile("^(?!py$)(py|pypy|jython)([2-9][0-9]?[0-9]?)?$")
CURRENT_RELEASE_ENV = "py37"
"""Should hold currently released py -> for easy updating"""
QUICKSTART_PY_ENVS = ["py27", "py34", "py35", CURRENT_RELEASE_ENV, "pypy", "jython"]
QUICKSTART_PY_ENVS = ["py27", "py35", "py36", CURRENT_RELEASE_ENV, "pypy", "jython"]
"""For choices in tox-quickstart"""


Expand Down
34 changes: 16 additions & 18 deletions tests/unit/config/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2190,26 +2190,24 @@ def test_no_implicit_venv_from_cli_with_envlist(self, newconfig):
assert "typo-factor" not in config.envconfigs

def test_correct_basepython_chosen_from_default_factors(self, newconfig):
envlist = list(tox.PYTHON.DEFAULT_FACTORS.keys())
config = newconfig([], "[tox]\nenvlist={}".format(", ".join(envlist)))
assert config.envlist == envlist
envs = {
"py": sys.executable,
"py2": "python2",
"py3": "python3",
"py27": "python2.7",
"py36": "python3.6",
"py310": "python3.10",
"pypy": "pypy",
"pypy2": "pypy2",
"pypy3": "pypy3",
"pypy36": "pypy3.6",
"jython": "jython",
}
config = newconfig([], "[tox]\nenvlist={}".format(", ".join(envs)))
assert set(config.envlist) == set(envs)
for name in config.envlist:
basepython = config.envconfigs[name].basepython
if name == "jython":
assert basepython == "jython"
elif name in ("pypy2", "pypy3"):
assert basepython == "pypy" + name[-1]
elif name in ("py2", "py3"):
assert basepython == "python" + name[-1]
elif name == "pypy":
assert basepython == name
elif name == "py":
assert "python" in basepython or "pypy" in basepython
elif "pypy" in name:
assert basepython == "pypy{}.{}".format(name[-2], name[-1])
else:
assert name.startswith("py")
assert basepython == "python{}.{}".format(name[2], name[3])
assert basepython == envs[name]

def test_envlist_expansion(self, newconfig):
inisource = """
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/interpreters/test_interpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def assert_version_in_output(exe, version):

p = tox_get_python_executable(envconfig)
assert p == py.path.local(sys.executable)
for major, minor in tox.PYTHON.CPYTHON_VERSION_TUPLES:
for major, minor in [(2, 7), (3, 5), (3, 6), (3, 7), (3, 8)]:
name = "python{}.{}".format(major, minor)
if tox.INFO.IS_WIN:
pydir = "python{}{}".format(major, minor)
Expand Down
25 changes: 15 additions & 10 deletions tests/unit/test_z_cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,26 +164,31 @@ def test_unknown_interpreter_and_env(cmd, initproj):
"interp123-0.5",
filedefs={
"tests": {"test_hello.py": "def test_hello(): pass"},
"tox.ini": """
[testenv:python]
basepython=xyz_unknown_interpreter
[testenv]
changedir=tests
skip_install = true
""",
"tox.ini": """\
[testenv:python]
basepython=xyz_unknown_interpreter
[testenv]
changedir=tests
skip_install = true
""",
},
)
result = cmd()
result.assert_fail()
assert any(
"ERROR: InterpreterNotFound: xyz_unknown_interpreter" == l for l in result.outlines
), result.outlines
assert "ERROR: InterpreterNotFound: xyz_unknown_interpreter" in result.outlines

result = cmd("-exyz")
result.assert_fail()
assert result.out == "ERROR: unknown environment 'xyz'\n"


def test_unknown_interpreter_factor(cmd, initproj):
initproj("py21", filedefs={"tox.ini": "[testenv]\nskip_install=true"})
result = cmd("-e", "py21")
result.assert_fail()
assert "ERROR: InterpreterNotFound: python2.1" in result.outlines


def test_unknown_interpreter(cmd, initproj):
initproj(
"interp123-0.5",
Expand Down

0 comments on commit 84c4c8d

Please sign in to comment.