¿Es posible utilizar tox con instalaciones Python basadas en conda?

La herramienta de prueba de Python parece estar diseñada para funcionar con virtualenv. ¿También puede funcionar en instalaciones Python basadas en conda / anaconda?

Sí, necesita la versión conda de virtualenv instalada para que esto funcione.

Tratar:

>conda install virtualenv

 virtualenv 15.1.0 py36_ 

Cambiar al directorio del proyecto que contiene tox.ini

>tox

Si bien tox no puede utilizar conda, puede usar conda para “instalar” diferentes versiones de Python donde tox puede encontrarlas (como si fuera a encontrar instalaciones “normales” de Python en esas carpetas). Lo siguiente está probado en Windows:

  1. Necesita virtualenv instalado a través de pip en el entorno root conda. Sospecho que este es el virtualenv que usará Tox. (Tuve que instalar virtualenv usando pip install virtualenv para que el comando virtualenv funcionara, aunque la conda list mostró como instalado).
  2. Instala las versiones de Python que quieres probar. Esto se hace fácilmente usando conda create . tox automáticamente los binarios de Python en Windows en C:\python27 , C:\python33 , etc., así que cree entornos usando conda create -p C:\python27 python=2.7 etc.

Hice que tox y conda trabajaran juntos en Windows al:

  • Instalando virtualenv con conda en el entorno que utilizo tox :

    conda install virtualenv

  • Creando enlaces simbólicos de “Directory Junction” desde C: \ PythonXY a mi ruta de entorno real. Esto evita el error de InterpreterNotFound :

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

He instalado Anaconda en E: \ Anaconda3 \ , y todos mis entornos en E: \ Anaconda3 \ envs \ , por ejemplo, E: \ Anaconda3 \ envs \ py27 \

(Vea a continuación un script para que esto sea rápido y fácil.)

Paso 1 – Crea ambientes con 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 

Paso 2 – Crea todos los enlaces simbólicos:

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

Nota: Llamo a conda create desde un directorio en la unidad E, por lo que no se requiere la opción --prefix / -p para instalar nuevos entornos en E: \ Anaconda3 \ envs \ .

Una manera más fácil:

En lugar de pasar por el engorroso proceso de configurar esto para cada entorno / versión de python, se puede usar la clase ToxEnvMatcher agregada más abajo de esta manera:

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

Edición : para hacer que el script sea más fácil de usar, agregué una nueva sección al archivo , (aquí se supone que es tox_with_conda.py ,) para que pueda llamarse desde cmd.exe:

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

Edit 2 : También se puede instalar con pip: pip install tox_with_conda y se usa como:

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

Estoy usando Python 3.6.3 y tox 2.9.1, pero no sé cuándo / si las versiones anteriores también funcionan.

Defensa : Supongo que para algunos, esto parece un proceso demasiado engorroso (aunque en realidad no lo es) o un gran truco. Pero tenga en cuenta que el hecho de poder utilizar Anaconda / conda también reduce la pérdida de tiempo que se tarda en instalar bibliotecas, paquetes, ++++.

Por favor tenga en cuenta :

  • Uso tox con pytest, y no he notado ningún impacto en mis pruebas.
  • Mis pruebas son simples y existe la posibilidad de que aún no haya sido expuesto a problemas.
  • Suponiendo, hay cosas en las que no he pensado que podrían ser relevantes para otros.

La clase (también disponible aquí ):

 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 `_ 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. Eg: 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'. Eg: given version='27' and environment folder ``{self.envs_dir}``: - ``conda create -p {self.envs_dir}\py27 python=2.7`` - ``mklink /JC:\Python27 {self.envs_dir}\py27`` :param str version: A string on the form 'XY', eg '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(' ') 

El código agregado para hacerlo funcionar desde cmd es:

 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. Eg '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) 

No sé qué tan desarrollado está, pero puede consultar https://github.com/hayd/ctox .