Skip to content

Commit

Permalink
Add support for pypy and none basepython (#142)
Browse files Browse the repository at this point in the history
  • Loading branch information
freundTech authored Jun 7, 2023
1 parent 2170e1e commit 98631aa
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 15 deletions.
11 changes: 7 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ With the plugin enabled and no other changes, the ``tox-conda`` plugin will use
``conda`` to create environments and use ``pip`` to install dependencies that are
given in the ``tox.ini`` configuration file.

``tox-conda`` adds four additional (and optional) settings to the ``[testenv]``
``tox-conda`` adds six additional (and optional) settings to the ``[testenv]``
section of configuration files:

* ``conda_deps``, which is used to configure which dependencies are installed
Expand Down Expand Up @@ -140,9 +140,12 @@ section of configuration files:
For instance, passing ``--override-channels`` will create more reproducible environments
because the channels defined in the user's ``.condarc`` will not interfer.

* If `mamba <https://mamba.readthedocs.io>`_ is installed in the same environment as tox,
you may use it instead of the ``conda`` executable by setting the environment variable
``CONDA_EXE=mamba`` in the shell where ``tox`` is called.
``tox-conda`` will usually install a python version compatible with your specified ``basepython``
to the conda environment. To disable this behavior set ``basepython`` to ``none``.

If `mamba <https://mamba.readthedocs.io>`_ is installed in the same environment as tox,
you may use it instead of the ``conda`` executable by setting the environment variable
``CONDA_EXE=mamba`` in the shell where ``tox`` is called.

An example configuration file is given below:

Expand Down
33 changes: 33 additions & 0 deletions tests/test_conda.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import shutil

import pytest
import tox
from tox.venv import VirtualEnv

import tox_conda.plugin

Expand Down Expand Up @@ -151,3 +153,34 @@ def test_issue_115(cmd, initproj):

result = cmd()
result.assert_success()


@pytest.mark.parametrize(
"basepython,expected",
[
("python3.8", ["python=3.8"]),
("python3.9", ["python=3.9"]),
("python3.10", ["python=3.10"]),
("pypy3.8", ["pypy3.8", "pip"]),
("pypy3.9", ["pypy3.9", "pip"]),
("none", []),
("None", []),
],
)
def test_python_packages(newconfig, mocksession, basepython, expected):
config = newconfig(
[],
"""
[testenv:test]
basepython={}
""".format(
basepython
),
)
venv = VirtualEnv(config.envconfigs["test"])
assert venv.path == config.envconfigs["test"].envdir

with mocksession.newaction(venv.name, "getenv") as action:
result = tox_conda.plugin.get_python_packages(config.envconfigs["test"], action)

assert set(result) == set(expected)
30 changes: 19 additions & 11 deletions tox_conda/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,23 @@ def postprocess_path_option(testenv_config, value):
return value


def get_py_version(envconfig, action):
def get_python_packages(envconfig, action):
if envconfig.basepython.lower() == "none":
return []

# Try to use basepython
match = re.match(r"python(\d)(?:\.(\d+))?(?:\.?(\d))?", envconfig.basepython)
match = re.match(r"(python|pypy)(\d)(?:\.(\d+))?(?:\.?(\d))?", envconfig.basepython)
if match:
groups = match.groups()
version = groups[0]
if groups[1]:
version += ".{}".format(groups[1])
version = groups[1]
if groups[2]:
version += ".{}".format(groups[2])
if groups[3]:
version += ".{}".format(groups[3])

if groups[0] == "pypy":
# PyPy doesn't pull pip as a dependency, so we need to manually specify it
return ["pypy{}".format(version), "pip"]

# First fallback
elif envconfig.python_info.version_info:
Expand All @@ -52,7 +59,7 @@ def get_py_version(envconfig, action):
result = action.popen([envconfig.basepython, "-c", code], report_fail=True, returnout=True)
version = result.decode("utf-8").strip()

return "python={}".format(version)
return ["python={}".format(version)]


@hookimpl
Expand Down Expand Up @@ -157,7 +164,7 @@ def tox_testenv_create(venv, action):

# Check for venv.envconfig.sitepackages and venv.config.alwayscopy here
envdir = venv.envconfig.envdir
python = get_py_version(venv.envconfig, action)
python_packages = get_python_packages(venv.envconfig, action)

if venv.envconfig.conda_env is not None:
env_path = Path(venv.envconfig.conda_env)
Expand All @@ -166,7 +173,8 @@ def tox_testenv_create(venv, action):
# in the conda-env.yml file
yaml = YAML()
env_file = yaml.load(env_path)
env_file["dependencies"].append(python)
for package in python_packages:
env_file["dependencies"].append(package)

tmp_env = tempfile.NamedTemporaryFile(
dir=env_path.parent,
Expand Down Expand Up @@ -197,11 +205,11 @@ def tox_testenv_create(venv, action):
# Add end-user conda create args
args += venv.envconfig.conda_create_args

args += [python]
args += python_packages

_run_conda_process(args, venv, action, basepath)

venv.envconfig.conda_python = python
venv.envconfig.conda_python_packages = python_packages

# let the venv know about the target interpreter just installed in our conda env, otherwise
# we'll have a mismatch later because tox expects the interpreter to be existing outside of
Expand Down Expand Up @@ -239,7 +247,7 @@ def install_conda_deps(venv, action, basepath, envdir):
# python in this environment. If any of the requirements are in conflict
# with the installed python version, installation will fail (which is what
# we want).
args += [venv.envconfig.conda_python] + conda_deps
args += venv.envconfig.conda_python_packages + conda_deps

_run_conda_process(args, venv, action, basepath)

Expand Down

0 comments on commit 98631aa

Please sign in to comment.