29

Python 测试工具tox似乎旨在与 virtualenv 一起使用。它也可以在基于 conda/anaconda 的 Python 安装上工作吗?

4

5 回答 5

11

tox-conda插件现在应该可以弥补这一差距,但需要积极使用 conda 的贡献者来测试和改进它。

从自述文件:

tox-conda是一个插件,为tox自动化工具提供与conda包和环境管理器的集成。这就像拥有你的蛋糕并吃它一样!

默认情况下,tox使用 [virtualenv]( https://virtualenv.pypa.io]创建隔离环境并从pip.

相反,在使用tox-conda插件时tox将使用conda创建环境,并从conda. 这对于依赖conda环境管理和包分发但希望利用tox测试自动化提供的功能的开发人员很有用。

要安装该插件,它需要与 tox 一起安装在同一个虚拟环境中。要创建一个包含tox并且tox-conda这应该足够的虚拟环境:

$ python3 -m venv toxbase
$ toxbase/bin/pip install tox tox-conda
[...]
Successfully installed tox-3.13.2 tox-conda-0.2.0
$ toxbase/bin/tox --version
3.13.1 imported from /home/ob/tmp/toxbase/lib/python3.6/site-packages/tox/__init__.py
registered plugins:
    tox-conda-0.2.0 at /home/ob/tmp/toxbase/lib/python3.6/site-packages/tox_conda/plugin.py

从那时起,tox 可以用作命令行工具,并通过在toxbasevirtualenv 中升级它来保持最新状态。另一种更自动化的方法是使用pipx

于 2019-08-26T08:16:48.900 回答
6

虽然 tox 不能使用 conda,但您可以使用 conda 在 tox 可以找到它们的地方“安装”不同的 Python 版本(就像它会在这些文件夹中找到“正常”的 Python 安装一样)。以下是在 Windows 上测试的:

  1. 您需要在根 conda 环境中virtualenv安装 via 。pip我怀疑这是 tox 将使用的 virtualenv。(我必须安装 virtualenv usingpip install virtualenv才能使virtualenv命令正常工作,即使它conda list显示为已安装。)
  2. 安装要测试的 Python 版本。这很容易使用conda create. tox将在 Windows 上自动检测 Python 二进制文件C:\python27C:\python33等,因此使用conda create -p C:\python27 python=2.7等创建环境。
于 2015-05-31T09:38:07.713 回答
6

是的,您需要virtualenv安装的 conda 版本才能正常工作。

尝试执行:

conda install virtualenv

virtualenv                15.1.0                   py36_

切换到包含tox.ini并执行的项目目录:

tox
于 2017-05-20T08:09:25.803 回答
4

我通过以下方式使 tox 和 conda 在 Windows 中协同工作:

  • virtualenv在我使用的环境中使用 conda安装tox

    conda install virtualenv

  • 从 C:\PythonXY创建“目录连接”符号链接到我的实际环境路径。这绕过了InterpreterNotFound-error:

    mklink /J C:\PythonXY C:\real\path\to\myPythonXYenv

我在 E:\Anaconda3\ 中安装了 Anaconda,E:\Anaconda3\envs\中安装了我的所有环境,例如E:\Anaconda3\envs\py27\

(请参阅下面的脚本,以使其快速简便。)

第 1 步- 使用 conda 创建环境:

E:\dev> conda create -n py27 python=2.7 --yes
E:\dev> conda create -n py33 python=3.3 --yes
...
E:\dev> conda create -n py36 python=3.6 --yes

第 2 步- 创建所有符号链接:

E:\dev> mklink /J C:\Python27 E:\Anaconda3\envs\py27
E:\dev> mklink /J C:\Python33 E:\Anaconda3\envs\py33
...
E:\dev> mklink /J C:\Python36 E:\Anaconda3\envs\py36

注意:conda create从 E 驱动器上的目录调用,因此不需要--prefix/选项就可以在E:\Anaconda3\envs\中安装新环境。-p

更简单的方法:

无需为每个环境/python版本进行繁琐的设置过程,可以使用ToxEnvMatcher以这种方式进一步添加的-class:

my_envs = os.path.join('E:\\', 'Anaconda3', 'envs')
tem = ToxEnvMatcher(my_envs)
for version in '27,34,35,36'.split(','):
    tem.make(version)

编辑:为了使脚本更易于使用,我在文件中添加了一个新部分,(这里假定为tox_with_conda.py,)因此可以从 cmd.exe 调用它:

C:\dev> python tox_with_conda.py E:\Anaconda3\envs 27 34 35 36 37

编辑 2:也可以使用 pip: 安装pip install tox_with_conda并用作:

C:\dev> python -m tox_with_conda E:\Anaconda3\envs 27 34 35 36 37

我正在使用 Python 3.6.3 和 tox 2.9.1,但我不知道早期版本何时/是否也可以工作。

防御:我认为对于某些人来说,这似乎是一个过于繁琐的过程(但实际上并非如此),或者对于很多黑客来说。但请记住,能够使用 Anaconda/conda 还可以减少尝试安装库、包、++++ 所花费的时间。

请注意

  • 我将 tox 与 pytest 一起使用,并没有注意到对我的测试有任何影响。
  • 我的测试很简单,而且我可能还没有遇到问题。
  • 假设,有些事情我没有想到可能与其他人相关。

课程(也可在此处获得):

from subprocess import run
from os.path import join

DEFAULT_BASE = join('C:\\', 'Python')


class ToxEnvMatcher:
    """
    Utility to make conda environments work with tox.

    Conda envs might be in other locations than where `tox <https://tox.readthedocs.io>`_ expects them to be.

    A symbolic link 'Directory Junction' is created from expected location to the actual location.
    Intended for Windows to get around the ``InterpreterNotFound``-error.

    E.g.: tox expects to find Python 2.7 in ``C:\Python27``,
    but may actually be installed in another drive and location.

    Examples of use:

    .. code-block:: python

        my_envs = join('E:\\', 'Anaconda3', 'envs')
        tem = ToxEnvMatcher(my_envs)
        for version in '27,34,35,36'.split(','):
            tem.make(version)

    The class is utilized through ``argsparse`` so it can also be used from cmd.exe.

    Examples of use of th of using ``ToxEnvMatcher`` from cmd.exe:

    .. code-block:: none

        E:\dev> tox_with_conda.py E:\Anaconda3\envs 27 34 35 36 37

    It's possible to use the ``-b``/``--base`` option to override the default base location (``C:\Python``):

    .. code-block:: none

        E:\dev> tox_with_conda.py E:\Anaconda3\envs 27 34 35 36 37 --base D:\Python

    :param str envs_dir: The path to where new conda environments will be created
    :param str default_base: The base of the 'default' location. Usually it's ``C:\Python``
    """
    def __init__(self, envs_dir, default_base=DEFAULT_BASE):
        self.envs_dir = envs_dir
        self.default_base = default_base

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, self.envs_dir)

    def make(self, version):
        """
        Take version and create conda environment with symlink from 'default tox location'.

        E.g.: given version='27' and environment folder ``{self.envs_dir}``:

         - ``conda create -p {self.envs_dir}\py27 python=2.7``
         - ``mklink /J C:\Python27 {self.envs_dir}\py27``

        :param str version: A string on the form 'XY', e.g. '27' or '36'
        :return: None
        :rtype: NoneType
        """
        if len(version) != 2 or not int(version):
            raise ValueError("Parameter 'version' must be on the form 'XY', and not '{}'".format(version))
        conda_cmd = self._create_cmd_args(version)
        symlink_cmd = self._create_symlink_args(version)
        run(conda_cmd, shell=True)
        run(symlink_cmd, shell=True)

    def _get_env_folder(self, version):
        return join(self.envs_dir, 'py{}'.format(version))

    def _create_cmd_args(self, version):
        env_dir = self._get_env_folder(version)
        python_version = '.'.join(version)
        conda_create = 'conda create -p {} python={} --yes'.format(env_dir, python_version)
        return conda_create.split(' ')

    def _create_symlink_args(self, version):
        env_dir = self._get_env_folder(version)
        return 'mklink /J {}{} {}'.format(self.default_base, version, env_dir).split(' ')

使其从 cmd 工作的添加代码是:

if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("env_dir",
                        help="The folder where conda environments should be installed.")
    parser.add_argument("versions", nargs='*',
                        help="The list of versions, formatted 'XY' where X is major and Y minor. E.g. '27 35 36'")
    parser.add_argument("-b", "--base", default=DEFAULT_BASE,
                        help="Base of the path which tox expects to find Python installed. "
                             "Default: {}.".format(DEFAULT_BASE))
    args = parser.parse_args()

    print('env_dir: ', args.env_dir)
    print('versions: ', args.versions)
    print('--base: ', args.base)

    tem = ToxEnvMatcher(args.env_dir, default_base=args.base)
    for version in args.versions:
        tem.make(version)
于 2017-12-06T04:01:26.687 回答
3

我不知道它的发展程度,但你可以看看https://github.com/hayd/ctox

于 2015-06-01T16:52:04.820 回答