classification
Title: The activate script in Windows is not correct for venvs created in git-bash
Type: behavior Stage:
Components: Windows Versions: Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Mo, bwanamarko, paul.moore, steve.dower, tim.golden, zach.ware
Priority: normal Keywords:

Created on 2019-10-24 14:32 by Mo, last changed 2020-04-15 05:32 by bwanamarko.

Messages (5)
msg355333 - (view) Author: (Mo) Date: 2019-10-24 14:32
When creating a virtual environment on Windows from git-bash (using python -m venv), VIRTUAL_ENV in the activate script is set using a windows style path (C:\some\path) instead of the bash style (/c/some/path).

This means the system python and pip get used, despite the user thinking they are working in a venv after sourcing activate.

As activate is a bash script, the paths in it should always be in the bash style, regardless of platform.

This is described in a stack overflow issue here: https://stackoverflow.com/questions/57758841/windows-virtualenv-created-via-gitbash-using-system-python

I have confirmed the behaviour in 3.7.3, 3.7.4, 3.7.5 and 3.8.0.
msg355356 - (view) Author: (Mo) Date: 2019-10-25 08:18
The issue comes as a result of abspath on line 59 of venv/__init__.py:
        env_dir = os.path.abspath(env_dir)

This returns a Windows-style path, and os.path.abspath returning in this way is *probably* correct, as the OS is Windows, despite trying to forget that by using bash.

It is still my view that the activate script is a bash script, and therefore should only contain paths in that style, but the simple solution to this issue is to change the double quotes around the definition of $VIRTUAL_ENV in the activate script to single quotes. It works. The output of "which python" is a bit odd, but this is clearly a quirk beyond Python's control.
msg355382 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2019-10-25 20:06
I agree this would be better, though it may not be that easy to do.

If you're running Windows Python from WSL, then your "bash style" path should be "/mnt/c/some/path", not "/c/some/path". So the answer isn't as simple as .replace('\\', '/').

I did some quick testing with posixpath and pathlib and neither has an obvious conversion from a Windows path to a POSIX path, though pathlib.PurePosixPath(pathlib.PureWindowsPath(p)) comes closest.

Perhaps the best approach here is to improve `activate` to determine its path when run, like we did for `activate.ps1`? Then we don't need to substitute the path in at creation time.
msg356146 - (view) Author: (Mo) Date: 2019-11-06 16:36
I had also tested with pathlib and posixpath and come to the same conclusion.

As suggested by you, I looked into `activate` determining path when run. I believe this should do the trick (My bashfoo isn't strong, this is mostly from https://stackoverflow.com/a/179231):

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}"
if ([ -h "${SCRIPT_PATH}" ]); then
  while([ -h "${SCRIPT_PATH}" ]); do cd `dirname "$SCRIPT_PATH"`; 
  SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
cd .. > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

VIRTUAL_ENV="$SCRIPT_PATH"
msg366488 - (view) Author: Mark Mikofski (bwanamarko) Date: 2020-04-15 05:32
Would you consider just handling activate for windows directly in the lib/venv/__init__.py method "install_scripts(self, context, path)"
https://github.com/python/cpython/blob/4f98f465f14e7258c5b18a62c5aa114dbe1174d8/Lib/venv/__init__.py#L382

    if not srcfile.endswith(('.exe', '.pdb')):

        # handle activate for Windows (ignore WSL)
        if srcfile == "activate":
            # from docs: on unix drive is always empty
            d, p = os.path.splitdrive(context.env_dir)
            d = d.replace(':', '')
            p = p.replace('\\', '/')
            if d:
                p = '/' + d + p
            data = data.decode('utf-8')
            data = data.replace('__VENV_DIR__', p)
            data = data.encode('utf-8')

        try:
            data = data.decode('utf-8')
            data = self.replace_variables(data, context)
            data = data.encode('utf-8')
        except UnicodeError as e:

IMHO I don't think the use of windows python in WSL is a realistic use-case, my preference would be to just make this fail. In fact I tried to use it, and I could not make it work.
1. /mnt/c/path/to/python -m venv venv
Error: [WinError 5] Access is denied: 'C:\\WINDOWS\\system32\\venv'
2. /mnt/c/path/to/python -m venv -m venv /mnt/c/some/path/to/venv
fails silently, appears to do nothing, venv is not created
3. /mnt/c/path/to/python -m venv -m venv 'C:/some/path/to/venv'
makes directories at C:\some\path\to\venv, but can't be activated in WSL, that I can figure out
source /mnt/c/some/path/to/venv/Scripts/activate
: command not found
-bash: /mnt/c/some/path/to/venv/Scripts/activate: line 4: syntax error near unexpected token `$'{\r''
'bash: /mnt/c/some/path/to/venv/Scripts/activate: line 4: `deactivate () {

I guess I don't really understand why it would be useful to use the windows python in WSL, and if that's the only thing holding a quick fix for this, I guess, I would prefer to just handle windows python in windows in git-bash, and ignore WSL. Would you be open to that?

If so, I'm happy to submit a PR

thanks!
History
Date User Action Args
2020-04-15 05:32:32bwanamarkosetnosy: + bwanamarko
messages: + msg366488
2019-11-06 16:36:02Mosetmessages: + msg356146
2019-10-25 20:06:48steve.dowersetmessages: + msg355382
versions: + Python 3.9, - Python 3.7, Python 3.8
2019-10-25 08:18:19Mosetmessages: + msg355356
2019-10-24 14:32:03Mocreate