Can I move a virtualenv?
Asked Answered
U

11

160

This question is not a duplicate.

It pertains not just to renaming a virtual environment, but to actually moving it to a different directory, including, potentially, a different user's directory.

This is not the same as merely renaming a virtual environment, especially to people unfamiliar with virtualenvs.

If I create a virtualenv, and I move it to a different folder, will it still work?

$ virtualenv -p /usr/bin/python3 /home/me/Env/my-python-venv
$ source Env/my-python-venv/bin/activate
(my-python-venv) $ 

...later that day, the virtual environment MOVED...

(my-python-venv) $ deactivate
$ mkdir -p /home/me/PeskyPartyPEnvs
$ mv /home/me/Env/my-python-venv /home/me/PeskyPartyPEnvs/

Question:

Will this work?

$ source /home/me/PeskyPartyPEnvs/my-python-venv/bin/activate
(my-python-venv) $ /home/me/PeskyPartyPEnvs/my-python-venv/bin/pip3 install foaas

I mean this as less of a question about the wisdom of trying this (unless that wisdom is humorous, of course), and more about whether it's possible. I really want to know whether it's possible to do in Python 3, or whether I just have to suck it up and clone it.

Can I just mv a virtualenv like that without sadness? I do want to avoid sadness.

Underneath answered 4/9, 2015 at 22:20 Comment(1)
Also, I found it misleading that the destination path may be relative (virtualenv ./my-python-venv) - suggesting it may be "portable". Restricting this destination to be an absolute-path would reinforce the notion that the virtualenv directory cannot-be/should-not be moved.Gang
U
19

BUT ALAS:

No, you can't simply mv. There are workarounds, but it might be easier to reinstall.

(my-python-venv)$ /home/me/PeskyPartyPEnvs/pip3 install foaas
zsh: /home/me/PeskyPartyPEnvs/pip3: bad interpreter: /home/me/Env/my-python-venv/bin/python3: no such file or directory
(my-python-venv)$ deactivate
$ 

... presses enter a lot in frustration, and the following works

$
$
$ pip3 search foaas

Except it is not from my-python-venv, ergo sadness.

Want to mv your virtualenv and use it, otherwise unmodified?

Short Answer:

I'll let Boromir say it, so he can make it clear:

Well, ya can't.

Underneath answered 4/9, 2015 at 22:27 Comment(6)
unless you want to get gory and modify it appropriately: It's the links in the binaries in the bin that cause the movement problem. If you know where you've come FROM you can use something like find bin -type f -exec ex -sc "%s,${FROM},${PWD},g|x" {} \; assuming your bin and lib are in your current venv folder. I use this as a quick and dirty way to copy and move python3 virtual envs with lots of pip packages installed.Objectivity
@PaulWhipp Is there any benefit to using that command versus just using --relocatable? Also, Nathan, great question but this a terrible answer. Accepting your own answer is always a little biased, unless it's well written and clearly enumerates the options, but determining that yourself would be subjective anyway.Precious
// , Haha yeah I guess it's pretty terribleUnderneath
@Precious --relocatable did not work for me but I routinely move python3 venvs by hacking the binaries and so far I've not had any problems.Objectivity
I was hinting that you should change accepted to a different (i.e. not yours) answer Perhaps the one chosen by the people :DPrecious
The question was "can I simply mv a venv?", and the answer is "no you can't simply mv, there are workarounds but it might be easier to reinstall". If this was the top answer, it would save me and others some time.Vahe
L
89

Yes. It is possible to move it on the same platform. You can use --relocatable on an existing environment.

From --help:

--relocatable -- Make an EXISTING virtualenv environment relocatable. This fixes up scripts and makes all .pth files relative.

HOWEVER, this does NOT seem to change the activate script, and rather only changes the pip* and easy_install* scripts. In the activate script, the $VIRTUAL_ENV environment variable hardcoded as the original /path/to/original/venv. The $VIRTUAL_ENV variable is used to set the PATH of your active environment too, so it must be changed based on the new location in order to call python and pip etc. without absolute path.

To fix this issue, you can change the $VIRTUAL_ENV environment variable in the activate script (for example using sed), and everything should be good to go.

An example of usage:

$ cd ~/first
$ virtualenv my-venv
$ grep 'VIRTUAL_ENV=' my-venv/bin/activate
VIRTUAL_ENV="/home/username/first/my-venv"
$ virtualenv --relocatable my-venv
Making script my-venv/bin/easy_install relative
Making script my-venv/bin/easy_install-2.7 relative
Making script my-venv/bin/pip relative
Making script my-venv/bin/pip2 relative
Making script my-venv/bin/pip2.7 relative
### Note that `activate` has not been touched
$ mkdir ~/second
$ mv my-venv ~/second
$ cd ~/second
$ grep 'VIRTUAL_ENV=' my-venv/bin/activate
VIRTUAL_ENV=/home/username/first/my-venv
### (This variable hasn't been changed, it still refers to the old, now non-existent directory!)
$ sed -i -e 's|username/first|username/second|' my-venv/bin/activate
## sed can be used to change the path.
## Note that the `-i` (in place) flag won't work on all machines. 
$ source my-venv/bin/activate 
(my-venv) $ pip install foass
...
(my-venv) $ python 
[...]
> import foass

Hooray, now you can install things and load them into your newly located virtual environment.

Lupitalupo answered 5/9, 2015 at 1:31 Comment(11)
// , Hm. This doesn't seem to actually end up making these relocatable. I keep getting some error about them not being "normal" script files.Underneath
Which scripts are not 'normal'? If I recall, the virtual env activate script mostly just changes environment variables. But if the python inside the virtualenv doesnt run on the new platform, then its probably not virtual env issue really, its issue of compiled program on different platforn. Can you run the normal python interpreter? Also, which shell are you using?Lupitalupo
"The --relocatable option currently has a number of issues, and is not guaranteed to work in all circumstances. It is possible that the option will be deprecated in a future version of virtualenv." (emphasis mine) see the user guideDinka
I tried this on windows and the error lists all the scripts (*.py, *.bat, *.ps1) in the Scripts dir (equivalent to bin on *nix) and says something like activate.ps1 cannot be made relative (it's not a normal script that starts with #!c:\..python.exe. basically it's complaining that the hash-bang in the file header is not the current virtualenv's python.exe, it's the one I moved it from -easy fixed. I looked in that posh script and it already discovers its own path anyway - nice. Some of the other scripts don't rely on paths either (e.g. deactivate.bat) so in short, this works.Precious
@Davos, so, to get this to work, you had to move the virtualenv with --relocatable AND modify the path to the Python binary at the start of some of the environment's scripts, right?Underneath
@NathanBasanese the message activate.ps1 cannot be made relative can be ignored because that script is already relative. The message is not helpful in Windows, because scripts don't use #! directives as in Linux to tell the shell which application should execute it. The activate.bat doesn't get modified, but it is not used (at least on windows 10, calling activate launches the PoSH script) so no I didn't need to edit any scripts. The problem is pip.exe which does have a path to python hard-coded and needs editing with a hex-editor, or just a reinstall.Precious
As Nelson noted in a comment to another answer, the python3 venv module does not support this flag. Mind if I edit it into your answer?Vahe
@Precious Thanks for the hexeditor tips regarding changing path in windows and the pip.exe file. It did the trick! :)Previdi
@Previdi In retrospect I would say don't do this. Your python environments should be easily recreate-able using at a minimum pip freeze to a requirements file so you can easily reinstall all your packages, docker (works well with virtualenv installed on it), conda, pyenv or some other tools. You should be able to create & destroy environments as immutable infrastructure, they shouldn't be precious.Precious
Is there anyway to switch to other virtual environment with Python IDEs such as Spyder?Neuburger
This was super handy for installing python packages I needed on a machine that didn't allow outgoing connections: just install locally in a venv, scp it to the classified system, update the activate script and working great! Didn't even have to use --relocatableSmear
E
73

For Python 3.3+ (with new venv built-in module)

Short Answer (regardless of version):

  • There's no clean, direct way to move a virtual environment
  • Just recreate, it's easy!!


Long Answer:

As of Python v3.3, the virtualenv package has become a built-in module named venv.

The --relocatable option mentioned in other answers has not been included in venv, and currently there is no good, safe way that I'm aware of to either rename or relocate a Python virtual environment.

However, it is fairly simple to recreate a virtual environment, with all its currently installed packages. See this answer, or see the section below. During the process you can recreate the new environment in whatever location and with whatever name you desire.

In the answer linked above, he mentions some 3rd party packages which may support direct renames or moves. If you are settled on pursuing a way to move a virtual environment, you could look into if those work with venv as well.

Note: In that answer, it is focused on virtualenv, rather than venv. See next section for how to translate.



venv vs. older virtualenv command syntax

The command to use venv is:

python -m venv

rather than just virtualenv, which installs as a command in the original package. Where "python" refers to however you run your python executable, which could be a variety of things, such as:

  1. python
  2. py or py -3.7 or similar (the Python Launcher for Windows for Python 3.3+ and bundled with Python for Windows, or the py package that can be installed separately for Linux [and MacOS?])
  3. python3 (convention for linux environments that dual install python 2 and 3)
  4. If you are having issues, use the absolute path to the python executable you want to run: e.g. c:\program files\python37\python.exe

If you are unsure which version is being run, you can always python --version to find out.



How to recreate a virtual environment

Creating/recreating a virtual environment is easy and should become second nature after you work with them for a bit. This process mirrors what you would do to distribute your script as a package (with it's dependencies) in the first half, and then what someone would do to install your script/package for further development.

First, get an updated list of what is in the virtual environment. With it active, get the Python version it uses and save out the list of dependencies to a file.

  1. Use python --version with the virtual environment activated to see what version of Python it is using.

    • This is for clarity - you may want to update the Python version for various reasons - at least to the latest patch version
    • For example, if the existing venv is using Python v3.7.4, but now v3.7.6 is out - use v3.7.6 instead, which should including only non-breaking security and bug fixes.
  2. Use python -m pip freeze > requirements.txt to create the list of current package dependencies and put them into the requirements.txt file. This command works in Linux or the Git Bash for sure - not 100% sure about Powershell or Command Line in Windows.

Now create a new virtual environment and then add the dependencies from the old one.

  1. Make your new venv.

    • Make sure you are using the correct version of python that you want to install to the venv.
    • If you want it to be exactly the same Python version:
      • While in the old venv, type "python --version", then make sure you create the new venv with that version of the python command.
    • For the new venv folder entry in the command:
      • Either add an absolute or relative path to the desired final folder location.
      • Use python -m venv my_new_venv to create a new virtual environment in the current working directory in a new my_new_venv folder.
      • The name of the venv folder will be the name of the venv (what shows up in the prompt when it is activated).
  2. Install your dependencies from the requirements.txt file.

    • python -m pip install -r requirements.txt

You might need to reinstall local packages that are in development mode.

Note, if you ever need to see the specific location a package is installed to, use:

  • python -m pip list -v
  • The -v or "verbose" option will add some extra information about each package that is installed, including the path it is installed in. This is useful to make sure you are keeping virtual, user, and system installed packages straight.

At this point you can just delete the old venv folder and all contents. I recommend using a GUI for that - file deletions are often permanent from the linux command line, and a small typo can be bad news.

Endodontics answered 8/11, 2019 at 18:37 Comment(14)
Is there no way of copying the venv pip state, i.e. without having to redownload all the libraries with pip?Singularity
I'm not sure the reason you would want to - is it due to an extremely low bandwidth situation to the internet or massive need to duplicate a lot? I believe you could get all the zips from pypi and then install locally, but I'm not up-to-speed on that. I do know you can setup a local pip server to host packages.Endodontics
The problem (that I am trying to solve) is that I want to run a python script on a machine that does not allow network traffic to pip (or, almost anywhere). I can put files on it, but it can't talk to pip. A niche case for sure but exactly why I need to move these things.Bondie
@RichardRast That's a different problem, I'm just answering the original question. Note: there are solutions to your issue (download packages as zips and locally install, run a PyPi mirror server behind your firewall, etc.), but this isn't the right :Q&A for that..Endodontics
You could create wheels from all of your packages with pip wheel . -w wheels and then just reinstall the packages in the new virtual environment with pip install --no-index --find-links /path/to/wheels/ -r requirements.txtTrebizond
You don't actually have to reinstall the modules. For me in python3.9, I simpy ran $ python3 -m venv new/path/to/virtenv again and it repaired the paths.Mathematician
python.exe implies windows OS which is not the case of the OP.Ichnite
Excellent answer, but one correction: when recreating the venv, you should NOT be in the current virtual environment. At least in python 3.6.8 on Linux, python is not copied into the venv, but a symbolic link to the current python binary. If you are in the original venv, python will point to the original venv instead of the system python.Zing
@KevinKeane Updated, per your suggestion.Endodontics
@Endodontics : In CI, I'm running stages in independent containers and want to cache the result of pip install for all subsequent stages. Since Jenkins for one insists on renaming workspaces (esp. inside parallel), venv with hard-coded paths break.Monkey
My virtual environment is 5.4gb is takes an 30+ minutes to install. "It's easy" is only true for some people.Appointment
@CalebFenton - "Easy" is different than "takes a while". I don't know why they don't support the option to move rather than recreate. I suspect there are a lot of "gotchas" and corner cases that break things. Feel free to provide an alternate solution or an improvement to this answer.Endodontics
It's not 30 minutes of installing and twiddling my thumbs, it's 30 minutes of hitting pip with a hammer to make it install everything, remember what's needed, compile everything correctly. The solution is to not use pip and use poetry, because it breaks in different ways.Appointment
Indeed, even having full network connectivity it's not going to be easy for a large project involving native code, on a Raspberry Pi, while the C compiler has seen a major upgrade since the original install.Anting
U
19

BUT ALAS:

No, you can't simply mv. There are workarounds, but it might be easier to reinstall.

(my-python-venv)$ /home/me/PeskyPartyPEnvs/pip3 install foaas
zsh: /home/me/PeskyPartyPEnvs/pip3: bad interpreter: /home/me/Env/my-python-venv/bin/python3: no such file or directory
(my-python-venv)$ deactivate
$ 

... presses enter a lot in frustration, and the following works

$
$
$ pip3 search foaas

Except it is not from my-python-venv, ergo sadness.

Want to mv your virtualenv and use it, otherwise unmodified?

Short Answer:

I'll let Boromir say it, so he can make it clear:

Well, ya can't.

Underneath answered 4/9, 2015 at 22:27 Comment(6)
unless you want to get gory and modify it appropriately: It's the links in the binaries in the bin that cause the movement problem. If you know where you've come FROM you can use something like find bin -type f -exec ex -sc "%s,${FROM},${PWD},g|x" {} \; assuming your bin and lib are in your current venv folder. I use this as a quick and dirty way to copy and move python3 virtual envs with lots of pip packages installed.Objectivity
@PaulWhipp Is there any benefit to using that command versus just using --relocatable? Also, Nathan, great question but this a terrible answer. Accepting your own answer is always a little biased, unless it's well written and clearly enumerates the options, but determining that yourself would be subjective anyway.Precious
// , Haha yeah I guess it's pretty terribleUnderneath
@Precious --relocatable did not work for me but I routinely move python3 venvs by hacking the binaries and so far I've not had any problems.Objectivity
I was hinting that you should change accepted to a different (i.e. not yours) answer Perhaps the one chosen by the people :DPrecious
The question was "can I simply mv a venv?", and the answer is "no you can't simply mv, there are workarounds but it might be easier to reinstall". If this was the top answer, it would save me and others some time.Vahe
L
7

YES, YOU CAN! (In windows)

The workaround is easy, just move your virtual environment anywhere then edit activate.bat inside scripts\:

  1. Move to the virtual environment to the desired directory

  2. Right-click and edit activate.bat located at venv_folder\scripts.

  3. Change VIRTUAL_ENV variable from:

     set VIRTUAL_ENV=C:\old_directory\venv_name
    

    into

     set VIRTUAL_ENV=C:\new_directory\venv_name
    
  4. Save the edited batch file, and thats it!

NOTE: My solution should work and save windows users setting up new virtual environments, I doubt this will work in other operating system since .bat is from MS-DOS

Lotte answered 2/11, 2020 at 12:13 Comment(3)
Change old_directory to old_directory - is that a typo?Emblements
// , I grit my teeth as I type this, but score one point for Windows.Underneath
To also go well in Pycharm, you should delete the current configuration from File->Settings...->Project->Python Interpreter->[down arrow]->Show All... and add the new one. Also, it might be required to deselect and select again the new interpreter of the current project configuration from [main view of Pycharm]->[project configuration name]->Edit Configurations...->Python Interpreter .Luftwaffe
U
6

The --relocatable argument to virtualenv appears to allow you to do this.

Unrig answered 4/9, 2015 at 23:59 Comment(4)
// , Does this just rely on relative paths, or does it monkey around somehow otherwise?Underneath
--relocatable works only existing virtual environments. Run virtualenv --relocatable my-python-venv AFTER the environment already exists.Lupitalupo
From --help: This fixes up scripts and makes all .pth files relative. No it is not going to make platform independent libraries. If you want to move it onto a different platform, you'd need to reinstall it based on the local python.Lupitalupo
the python3 venv module does not support this flagInterval
E
5

Yes, this should be possible if you haven't done anything that depends on the current directory of the virtualenv.

However, if you have the choice, the best thing to do is to create new virtualenv and start using the new virtualenv instead. This is the safest choice and least likely to cause issues later.

The documentation does mention that:

Each virtualenv has path information hard-coded into it,

For example, if you have run setvirtualenvproject then it won't be able to switch to the right directory after you run workon ... so in that case you'd need to fix that manually.

In general a virtualenv is little more than a directory with the necessary Python interpreter files plus packages that you need.

Emoryemote answered 4/9, 2015 at 22:24 Comment(0)
B
4

Using answers of this and other threads about similar topic, I've made a bash script that, located and executed within the virtualenv directory itself, will help with your virtualenv moves.

After doing virtualenv --relocatable yourenv you'll need to change your VIRTUAL_ENV variable every time you move the directory, so if you don't wan't to change it manually, use this.

#!/bin/bash \n 
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
EXISTING=$(grep 'VIRTUAL_ENV=' bin/activate)  
NEWDIR=VIRTUAL_ENV=\"$DIR\"
sed -i -e "s|$EXISTING|$NEWDIR|" bin/activate
source bin/activate

I hope it helps.

Bichloride answered 12/10, 2019 at 16:59 Comment(0)
M
4

We can share storage for large modules between virtual environments by creating a hard link copy of the base environment, then updating paths using this venv_move script.

cd /opt
cp -al python3.10-ai python3.10-fastai
venv_move python3.10-fastai

The first argument is the path to the venv. It deletes any __pycache__ under that path.

It detects the old path, and replaces it with the current path, after confirming. Then it does similarly for the venv name in the activate scripts. It seems to work okay, even when moving to a different machine of the same type.

The script relies on bash and GNU sed, i.e. it works on Linux and not necessarily on Mac OS or Windows. It would make sense to re-write it in Python for non-Linux users.

#!/bin/bash -eu
venv=${1%/}

find "$venv" -name __pycache__ | xargs rm -rf --

old=`perl -ne '/VIRTUAL_ENV="(.*?)"/ && print "$1\n"' "$venv/bin/activate"`
new=$PWD/$venv

old2="(`basename "$old"`)"
new2="(`basename "$venv"`)"

if [ "$old" = "$new" ]; then
    echo "venv paths are already set correctly to $new"
else
    files=`fgrep -r "$old" "$venv" -l`
    echo "$files"
    echo "Replace $old with $new in the above files?"
    read -p "[yn] ? " YN
    if [ "$YN" = y ]; then
        sed -i "s:$old:$new:g" $files
    fi

    files=`fgrep -r "$old2" "$venv"/bin/activate* -l`
    echo "$files"
    echo "Replace $old2 with $new2 in the above files?"
    read -p "[yn] ? " YN
    if [ "$YN" = y ]; then
        sed -i "s:$old2:$new2:g" $files
    fi
fi
Midships answered 15/6, 2021 at 3:41 Comment(3)
// , "It would make sense to re-write this in Python" awwww yiss. I may just take you up on that, Mr. Watkins.Underneath
Why it would make sense to re-write it in python ? I don't see any benefits to do so. This script is fine.Ichnite
@Ichnite some people use Windows, non-GNU sed or whateverMidships
R
2

TL;DR

virtualenv-clone is included part of virtualenvwrapper

virtualenv-clone /path/to/old/venv /path/to/new/venv

Alternatively

You could also try cpvirtualenv

cpvirtualenv /path/to/old/venv /path/to/new/venv

But cpvirtualenv expects the /path/to/old/venv to be existing inside $WORKON_HOME and if it isn't it fails. Since this calls virtualenv-clone you may as well use that instead; to avoid errors like

mark@Desktop:~/venvs$ cpvirtualenv ./random/ $WORKON_HOME/random
Copying random as /home/mark/.virtualenvs/venvs/random...
Usage: virtualenv-clone [options] /path/to/existing/venv /path/to/cloned/venv

virtualenv-clone: error: src dir '/home/mark/.virtualenvs/venvs/random' does not exist

Warning as per virtualenvwrapper documentation

Copying virtual environments is not well supported. Each virtualenv has path information hard-coded into it, and there may be cases where the copy code does not know it needs to update a particular file. Use with caution.

What does it actually do ? As per virtualenv-clone PyPi page

A script for cloning a non-relocatable virtualenv.

Virtualenv provides a way to make virtualenv's relocatable which could then be copied as we wanted. However making a virtualenv relocatable this way breaks the no-site-packages isolation of the virtualenv as well as other aspects that come with relative paths and /usr/bin/env shebangs that may be undesirable.

Also, the .pth and .egg-link rewriting doesn't seem to work as intended. This attempts to overcome these issues and provide a way to easily clone an existing virtualenv.

It performs the following:

copies sys.argv[1] dir to sys.argv[2]

updates the hardcoded VIRTUAL_ENV variable in the activate script to the new repo location. (--relocatable doesn't touch this)

updates the shebangs of the various scripts in bin to the new Python if they pointed to the old Python. (version numbering is retained.)

it can also change /usr/bin/env python shebangs to be absolute too, though this functionality is not exposed at present.

checks sys.path of the cloned virtualenv and if any of the paths are from the old environment it finds any .pth or .egg link files within sys.path located in the new environment and makes sure any absolute paths to the old environment are updated to the new environment.

finally it double checks sys.path again and will fail if there are still paths from the old environment present.

NOTE: This script requires Python 2.7 or 3.4+

Rhaetian answered 5/6, 2021 at 12:48 Comment(0)
A
1

As said, there are ways to do so. The best tool so far should be venv-pack. One command to do so, while it does the hard work of removing the hardcoded VIRTUAL_ENV variable so once packed, the venv can be put into anywhere and still works.

Adamski answered 7/10, 2023 at 17:57 Comment(0)
A
0

You can

Recently we had to delete some users at our servers, but some of them had legacy code. I knew it so I moved all the data to some new directory. A moment has come to run some legacy code using some legacy environment, but unfortunately it didn't work.

pip didn't work so I couldn't get a neat freeze requirements.txt, and I was super lazy to install packages one by one from lib/site-packages. So I decided to look for a workaround.

The workaround: I changed all the old environment paths in bin/activate* and bin/pip* files and also replaced bin/python* link referrals (the links were broken). It worked after it. Not sure if all the changes are obligatory, but still this information might be of use.

Arnone answered 20/7, 2023 at 16:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.