Skip to content

Problem using virtualenvwrapper on Windows with git bash #124

Open

Description

@julie777

I found two issues that I want to report. I am sorry that I do not have the time to submit a pull request.

  1. In the doc, it mentions that to use on Windows with MSYS that the MSYS_HOME variable needs to be set.
    In the Installation section under MSYS
    export MSYS_HOME=/c/msys/1.0
    On my system that needs to be
    export MSYS_HOME=/c/msys64/usr
    because there is no bin directory under msys64 so it needs /usr to be able to fins sh.exe in user_scripts.py _get_sys_shell()

This really just a doc problem, but I did have to go looking to find out why running postmkvirtualenv was failing in mkproject.

NOTE: I do think that MSYS_HOME as the variable name is not reflecting that it is needed for virtualenvwrapper.

  1. There is a path issue when trying to connect the virtualenv to the project in mkproject. The issue is that python on windows, even running under bash uses Windows/non-posix style paths. This often leads to mixing of separators and the drive: prefix.

My fix was to remove the use of python to convert paths to absolute and expand vars, etc. Instead I switched to readlink. In the two functions: virtualenvwrapper_expandpath and virtualenvwrapper_absolutepath I just changed the the single line modifying the filepath variable.

    << "$VIRTUALENVWRAPPER_PYTHON" -c "import os,sys; ...
    >> readlink -f "$1"

I have confirmed that it works on MSYS and Debian.

Thanks for continuing to support the project!

Activity

  1. ferdnyc commented on May 4, 2026

    @ferdnyc
    Contributor

    @julie777

    1. In the Installation section under MSYS
      export MSYS_HOME=/c/msys/1.0
      On my system that needs to be
      export MSYS_HOME=/c/msys64/usr
      because there is no bin directory under msys64 so it needs /usr to be able to fins sh.exe in user_scripts.py _get_sys_shell()

    Mmm, then you're using MSYS2, specifically... but so would anyone else using MSYS these days. Having commands for MSYS 1.0 in the docs is really pretty useless as it's been supplanted by MSYS2 for something like a decade now. MSYS2 doesn't use $MSYS_HOME, it uses the $MSYSTEM and $MSYSTEM_PREFIX variables to determine when a shell/process is running under an MSYS2 installation, and those are already set when Git Bash launches.

    The virtualenvwrapper.sh script also already uses the $MSYSTEM variable to detect when it should go into Windows-paths mode — $MSYS_HOME is pretty much meaningless these days, and probably shouldn't be used in user_scripts.py either. In fact, NOT setting $MSYS_HOME is the right way to go, because a Git Bash session will have sh.exe in its default $PATH, which user_scripts.py will fall back to if it DOESN'T see an $MSYS_HOME shell variable set.

    What it comes down to is, both the code and the docs (I assume you're referring to the Install > MSYS section of the docs) appear to be somewhat out of date, when it comes to Windows support. They should be updated for Git Bash and MSYS2, which is how anyone on Windows will be using virtualenvwrapper these days — not via MSYS 1.0.

    My fix was to remove the use of python to convert paths to absolute and expand vars, etc. Instead I switched to readlink.

    Yeah, there's an unfortunate problem with that approach... macOS doesn't have a readlink command. Believe me, there are about 100 software projects I've contributed to that could all be SO MUCH simpler if macOS just had a readlink command!

    The problem with virtualenvwrapper.sh, when running against a Windows Python installation (like C:\Python314/python.exe) is that it tries to do a which python3 to find the appropriate Python executable, and Windows Python doesn't install a python3.exe executable/script.

    If the wrapper script instead ran which python, it would get a path like /c/Python314/python (the unix-style equivalent of C:\Python314\Python.exe), and it would be able to use that executable to convert paths.

    (Windows-style paths aren't actually a problem in Git Bash, as Python supports both path styles and the shell does automatic conversion where necessary. ls C:\\Users\\ will actually work just fine in Git Bash, and is the same as running ls C:/Users/ which is the same as running ls /c/Users/. The issue is the lack of a python3 command to run.)

    It might be possible to have the virtualenvwrapper.sh script leverage its existing $MSYSTEM-based Windows environment detection, and have it switch the which python3 command to which python automatically, since that's more appropriate for that environment.

    Right now that detection is done here:

    # Define script folder depending on the platorm (Win32/Unix)
    VIRTUALENVWRAPPER_ENV_BIN_DIR="bin"
    if [ "${OS:-}" = "Windows_NT" ] && ([ "${MSYSTEM:-}" = "MINGW32" ] || [ "${MSYSTEM:-}" = "MINGW64" ])
    then
    # Only assign this for msys, cygwin use standard Unix paths
    # and its own python installation
    VIRTUALENVWRAPPER_ENV_BIN_DIR="Scripts"
    fi

    ...which is after the $VIRTUALENVWRAPPER_PYTHON setup. But there's nothing there that would prevent it from being moved before the Python checks.

  2. ferdnyc commented on May 4, 2026

    @ferdnyc
    Contributor

    All of this is only relevant if you actually want to use a Windows Python installation for your virtual environment, like in that docs section I linked to above.

    If you're fine with using a Unix-style Python as the virtual environment Python executable (like the one installed to C:\msys64\usr\bin\python3.exe), then the easiest approach is to use the "MSYS2 MSYS" launcher installed by MSYS2 to run Bash, instead of Git Bash. "MSYS2 MSYS" will drop you into a Bash shell that's largely disconnected from the Windows parts of the system, with its local $MSYSTEM_PREFIX/usr/bin/ directory already at the front of your $PATH. Then, the which python3 command run by virtualenvwrapper.sh will successfully locate /usr/bin/python3, avoiding all of the problems above.

    (You have to make sure that pip install virtualenvwrapper is first run from that same shell environment, though. It won't work in the MSYS2 MSYS shell if it's installed to a Windows Python installation — which includes the ones you'd typically use in Git Bash.)

  3. carltongibson commented on May 4, 2026

    @carltongibson
    Contributor

    @ferdnyc Do you think this issue is out of scope really, and can be closed? (The docs do very much punt of Windows support.)

  4. ferdnyc commented on May 6, 2026

    @ferdnyc
    Contributor

    @carltongibson IMHO no. Since virtualenvwrapper doesn't supply a PowerShell activation script, being able to run the Bash script under Windows has value.

    And anyway, if I'm right it should be easy to fix. The only thing it's doing wrong is running which python3 when attempting to discover a Python runtime in the $PATH. But with Python 2 now well past EOL, which python should find a Python 3 binary anywhere, so that could probably be changed to which python across-the-board.

    And even if not, having it detect when it's running under Windows and using which python instead is trivial. The script is ALREADY detecting Windows, it's just that it currently happens right after the which python3.

  5. carltongibson commented on May 6, 2026

    @carltongibson
    Contributor

    I think the correct approach on windows then is to use the py launcher tool to find installed Pythons.

    (Although as I write that I'm not certain it's always available, if installing from the Windows App Store)

  6. ferdnyc commented on May 6, 2026

    @ferdnyc
    Contributor

    There's a bigger problem with using py. We'd really want to give it an argument (like py -3 to run some version of Python 3), and it looks like it would take some restructuring to make $VIRTUALENVWRAPPER_PYTHON support a command with arguments. Right now it's a non-array variable that's typically called inside double-quotes. (Also, things like the which command would have to know to just run which py, even though the VIRTUALENVWRAPPER_PYTHON command would be py -3.)

    I think if any version of Windows Python is installed, py can be relied on to be there... so if it's not, we probably don't have a usable Python either.

  7. ferdnyc commented on May 6, 2026

    @ferdnyc
    Contributor

    (In fact, it looks like py is not only compatible with Windows Store installs, but it supports auto-install of the requested version!)

    $ py -2
    No suitable Python runtime found
    Pass --list (-0) to see all detected environments on your machine
    or set environment variable PYLAUNCHER_ALLOW_INSTALL to use winget
    or open the Microsoft Store to the requested version.

    ...mind you, it doesn't appear to work very well:

    $ py --list
     -V:3.14 *        Python 3.14 (64-bit)
    $ Set-Item Env:PYLAUNCHER_ALLOW_INSTALL 1
    $ py -3.13
    Launching winget to install Python. The following output is from the install process
    ***********************************************************************
    Found an existing package already installed. Trying to upgrade the installed package...
    No available upgrade found.
    No newer package versions are available from the configured sources.
    ***********************************************************************
    Please check the install status and run your command again.

    But, maybe that's because I'm still on Windows 10.

  8. ferdnyc commented on May 6, 2026

    @ferdnyc
    Contributor

    py appears to be doing something stupid, because winget install Python.Python.3.13 (which is what it should be running itself) worked just fine to install that runtime.

    (Edit: Aha. If I try to run winget install -s msstore "Python 3.12" (which is how it's listed there, nothing like machine-readable identifiers 🙄), then it fails the same way because Python 3.14 is already installed. But winget install -s msstore --force "Python 3.12" works, and without removing Python 3.14. You'd think py would know it has to --force the installs, if it's going to bother providing that feature at all.)

  9. ferdnyc commented on May 6, 2026

    @ferdnyc
    Contributor

    UGGGGGGh. So it turns out, I was using an old version of the py command, from the "Python Launcher" package. Which is not the same as the new, improved py / pymanager from the Python Install Manager package, as now recommended by https://docs.python.org/dev/using/windows.html

    When using the new py:

    • The command to launch a specific Python version becomes something like py -V:3.14, or preferably even py exec -V3.14 ­- but the multiple-arguments issue is still there
    • py exec will automatically install missing runtimes by default, without needing an environment variable.1
    • A python3 command is actually installed, as a Windows "App execution alias", so which python3 would work to find a runtime

    ...However, that same Python documentation page recommends against using python3 as the Python command. It actually recommends using just python, assuming the runtime's dir is in the user's %PATH%, although py / py exec are available to run with specific versions or versions that might not be in the path.

    So, at the very least, ignore everything I said about py and which python3 before this comment.

    Notes

    1. (And it actually works:)
    $ py exec -V:3.12 -m site
    ********************************************************************************
    Installing Python 3.12.10.
    Downloading: ..................................................................?
    Extracting: ...................................................................?
    To see all available commands, run 'py help'
    ********************************************************************************
    sys.path = [
        'C:\\Users\\$ME',
        'C:\\Users\\$ME\\AppData\\Local\\Python\\pythoncore-3.12-64\\python312.zip',
        'C:\\Users\\$ME\\AppData\\Local\\Python\\pythoncore-3.12-64\\DLLs',
        'C:\\Users\\$ME\\AppData\\Local\\Python\\pythoncore-3.12-64\\Lib',
        'C:\\Users\\$ME\\AppData\\Local\\Python\\pythoncore-3.12-64',
        'C:\\Users\\$ME\\AppData\\Roaming\\Python\\Python312\\site-packages',
        'C:\\Users\\$ME\\AppData\\Local\\Python\\pythoncore-3.12-64\\Lib\\site-packages',
    ]
    USER_BASE: 'C:\\Users\\$ME\\AppData\\Roaming\\Python' (exists)
    USER_SITE: 'C:\\Users\\$ME\\AppData\\Roaming\\Python\\Python312\\site-packages' (exists)
    ENABLE_USER_SITE: True
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions