I don’t want to learn, skip to solution

If you’re using brew to manage your packages on Mac (and if you’re not, you should) you might have encontered issues after updating Python in a virutalenv that look like this:

dyld: Library not loaded: @executable_path/../.Python
  Referenced from: /Users/garettmd/venv/testapp/bin/python
  Reason: image not found
Abort trap: 6

What’s happening here is the symlinks in your virtualenv are pointing to a non-existant executable. From the first line of the error you can see that it’s looking at the .Python symlink in the base directory for the virutalenv. If you ls on it, you’ll see something like

lrwxr-xr-x 79 garettmd 10 Aug  2017 .Python -> /usr/local/Cellar/python3/3.6.2/Frameworks/Python.framework/Versions/3.6/Python

If you ls on that expanded location, you’ll see that it doesn’t exist. You could fix this by manually fixing the symlink to point to the new location (by changing the version in this case). However, if you take a look around some of the other directories in the virutalenv, you’ll see a lot of other symlinks in play, especially in the lib directory. Rather than fixing these by hand, or even using some bash for loops, the simplest fix I’ve found (thanks to StackOverflow…) is to delete all the symlinks, and just run virtualenv on the…virtualenv to regenerate all the symlinks again.

# This is for installing gfind (GNU find) which allows you to search for broken symlinks
brew install findutils

# First show the broken symlinks (you can skip this, but it's educational 😄)
gfind ~/.venv/my-virtual-env/ -type l -xtype l
# Then delete them
gfind ~/.venv/my-virtual-env/ -type l -xtype l -delete
# Now re-create them
virtualenv ~/.venv/my-virtual-env

Note that I’m using gfind (GNU find) here because it allows you to show only broken symlinks. You could just as well use find ~/venv/testapp -type l -delete, but that will also delete any symlinks that aren’t broken. This is probably fine most of the time, but if you’ve created your own symlinks outside of the virtualenv command, those would get deleted too, but not recreated when you ran virtualenv afterward.