tox-dev / tox-conda

Make tox cooperate with conda envs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

conda environment paths not added

marlonjames opened this issue · comments

Environment: Windows 10, miniconda3 (Python 3.8.3, conda 4.8.3), tox 3.20.1

Essentially it doesn't add the default paths for each tox-created environment that would normally be added by conda activate.

In my example, I was trying to compile something with msys2, and if you don't have the msys2 packages installed in the base environment but put them under conda_deps in tox.ini, it won't work.

I added this as a workaround:

[testenv]
# tox-conda doesn't add conda environment paths to PATH so here's a workaround
setenv =
    PATH = {envdir}{:}{envdir}/Library/mingw-w64/bin{:}{envdir}/Library/usr/bin{:}{envdir}/Library/bin{:}{envdir}/Scripts{:}{envdir}/bin{:}{env:PATH}

@garmin-mjames I think this may be fixed in tox conda 0.4.0 (see discussion at bottom of #48), can you check?

@jhkennedy I was looking at this yesterday, and my solution above doesn't actually fix things in all cases, and it's still broken in 0.4.0 on Windows.

When a tox command is run, two things relating to this issue happen:

  1. getcommandpath() is called to try to locate the command (https://github.com/tox-dev/tox/blob/7df5b9ae1761a28aec0ffb6e220572782bbd995a/src/tox/venv.py#L591)
    a. try _venv_lookup()
    b. if not found, try _normal_lookup()
    c. if not found, raise InvocationError
  2. action.popen() is called to run the command (https://github.com/tox-dev/tox/blob/7df5b9ae1761a28aec0ffb6e220572782bbd995a/src/tox/venv.py#L596)

The problem is that 1 above doesn't use the env object at all, so if the executable isn't found by _venv_lookup() or in os.environ['PATH'], it won't get to step 2. Step 2 uses env and so will use the path modified with setenv.

The real solution is two-fold:

  1. Update the monkey-patched _venv_lookup() function to use the default conda paths on Windows:

    • self.envconfig.envdir
    • self.envconfig.envdir.join("Library", "mingw-w64", "bin")
    • self.envconfig.envdir.join("Library", "usr", "bin")
    • self.envconfig.envdir.join("Library", "bin")
    • self.envconfig.envdir.join("Scripts") - same as self.envconfig.envbindir
    • self.envconfig.envdir.join("bin")
  2. Add these paths to the env for VirtualEnv._pcall(). I'm not sure if the right approach is to use setenv["PATH"] in tox_configure() for each testenv, or monkey-patch _pcall().

It might also be appropriate to remove the directories of the conda environment that was used to run tox, to further align with conda activate behavior.

Edit: something like https://github.com/conda/conda/blob/6d1fea1164fcea27a59825adad2b83af72632db3/conda/activate.py#L593

We build python extensions with cmake (and pybind). Cmake is seen but it cannot locate not the gcc compilers/tools.
These are not in PATH but in environment variable set by "conda activate" when CONDA_BUILD is defined.

I tried to define CONDA_BUILD and activate the base environment before launching tox and allowing it to get all the needed environment variables (passenv=CONDA_BUILD ADDR2LINE AR AS CC CFLAGS CMAKE_PREFIX_PATH CONDA_BUILD_SYSROOT _CONDA_PYTHON_SYSCONFIGDATA_NAME CPP CPPFLAGS CXX CXXFILT CXXFLAGS DEBUG_CFLAGS DEBUG_CPPFLAGS DEBUG_CXXFLAGS ELFEDIT GCC GCC_AR GCC_NM GCC_RANLIB GPROF GXX HOST LD LDFLAGS LD_GOLD NM OBJCOPY OBJDUMP RANLIB READELF SIZE STRINGS STRIP), and the C compiler is seen but this is the one of the base environment, not the one one the newly created environment and if a library is needed, say libnetcdf, it may not be seen).
When I run tox on my development computer, it generally works because things are seen from the system, but when run in CI with docker, tools are only in conda environments.
We build our project modules for python 3.7, 3.8 and 3.9 and versions of packages are not always the same.
When building packages it is good since conda-build creates and activates the environment correctly. But not with tox since it installs the source with pip.

@marlonjames and @ppoilbarbe
tox-conda 0.8 should address this kind of issues (although not perfectly), you may give it a try.

I'm using 0.8, but I'm still seeing behavior that I think is related to this on Windows. I believe that numpy 1.20 changed the way that they load DLLs and it falls apart if the PATH variable isn't setup properly to find them. The output below is what I get if I run tox-conda (or if I try to run import numpy from a non-activated conda env). If I do conda activate then do import numpy, it works fine. I haven't found a way to work around this issue as of yet.

15:31:24    from . import _distributor_init
15:31:24  Failure: ImportError (
15:31:24  
15:31:24  IMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!
15:31:24  
15:31:24  Importing the numpy C-extensions failed. This error can happen for
15:31:24  many reasons, often due to issues with your setup or how NumPy was
15:31:24  installed.
15:31:24  
15:31:24  We have compiled some common reasons and troubleshooting tips at:
15:31:24  
15:31:24      https://numpy.org/devdocs/user/troubleshooting-importerror.html
15:31:24  
15:31:24  Please note and check the following:
15:31:24  
15:31:24    * The Python version is: Python3.8 from "D:\Jenkins\ossjml01\workspace\swat-python_win-64\tox\py38-pip-cicd\python.exe"
15:31:24    * The NumPy version is: "1.20.2"
15:31:24  
15:31:24  and make sure that they are the versions you expect.
15:31:24  Please carefully study the documentation linked above for further help.
15:31:24  
15:31:24  Original error was: DLL load failed while importing _multiarray_umath: The specified module could not be found.
15:31:24  ) ... ERROR

Yeah, I'm not convinced that conda run is the full answer. As far as I understand it is still considered Experimental.

Does anyone have a work around (hack or otherwise)? This is a major holdup in one of my projects. I tried using the setenv trick from the original post, but that didn't work for me.

@kesmit13 The following works for me, does it for you?

conda create -n foo python=3.8 numpy
conda run -n foo python t.py

where t.py contains import numpy.

@AntoineD That does work for me, but for some reason environments like that don't work in Jenkins as seen above. I'm not sure what the difference is though.

Sorry I do not use Jenkins, I do not know how to help you.

I started digging into this some more. I'm still not sure why it isn't working on Windows, but I did an update of the tox package and the setenv workaround from the original post started working for me.