Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does activating a python virtual environment modify sys.path?

I create my python virtual environment using:

python3 -m venv venv3

to activate, I source venv3/bin/activate.

venv3/bin/activate doesn't appear to be all that complex:

# This file must be used with "source bin/activate" *from bash*
# you cannot run it directly

deactivate () {
    # reset old environment variables
    if [ -n "$_OLD_VIRTUAL_PATH" ] ; then
        PATH="$_OLD_VIRTUAL_PATH"
        export PATH
        unset _OLD_VIRTUAL_PATH
    fi
    if [ -n "$_OLD_VIRTUAL_PYTHONHOME" ] ; then
        PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME"
        export PYTHONHOME
        unset _OLD_VIRTUAL_PYTHONHOME
    fi

    # This should detect bash and zsh, which have a hash command that must
    # be called to get it to forget past commands.  Without forgetting
    # past commands the $PATH changes we made may not be respected
    if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
        hash -r
    fi

    if [ -n "$_OLD_VIRTUAL_PS1" ] ; then
        PS1="$_OLD_VIRTUAL_PS1"
        export PS1
        unset _OLD_VIRTUAL_PS1
    fi

    unset VIRTUAL_ENV
    if [ ! "$1" = "nondestructive" ] ; then
    # Self destruct!
        unset -f deactivate
    fi
}

# unset irrelevant variables
deactivate nondestructive

VIRTUAL_ENV="/home/pi/django-test/venv3"
export VIRTUAL_ENV

_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/bin:$PATH"
export PATH

# unset PYTHONHOME if set
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
# could use `if (set -u; : $PYTHONHOME) ;` in bash
if [ -n "$PYTHONHOME" ] ; then
    _OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME"
    unset PYTHONHOME
fi

if [ -z "$VIRTUAL_ENV_DISABLE_PROMPT" ] ; then
    _OLD_VIRTUAL_PS1="$PS1"
    if [ "x(venv3) " != x ] ; then
    PS1="(venv3) $PS1"
    else
    if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then
        # special case for Aspen magic directories
        # see http://www.zetadev.com/software/aspen/
        PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1"
    else
        PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1"
    fi
    fi
    export PS1
fi

# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands.  Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
    hash -r
fi

I can see it modifying $PATH, and $PS1, creating a deactivate function, and even backing up old variables that it modifies so it can restore them when the user runs the deactivate function. All this makes sense.

The one thing I don't see is where python's sys.path is modified. On my system, this is what I see:

sys.path outside of virtual environment:

['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-arm-linux-gnueabihf', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']

sys.path inside of virtual environment:

['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-arm-linux-gnueabihf', '/usr/lib/python3.5/lib-dynload', '/home/pi/django-test/venv3/lib/python3.5/site-packages']

Clearly, sys.path gets modified at some point, somehow. This makes sense, since that's how python knows where to find the third-party python libraries that are installed. I would think that this is the main feature of the virtual environment, but I can't see where it gets set.

I'm not trying to accomplish anything - mostly just curious.

like image 813
John Avatar asked Feb 25 '19 17:02

John


People also ask

What does activating a Python virtual environment do?

Activating a virtual environment Before you can start installing or using packages in your virtual environment you'll need to activate it. Activating a virtual environment will put the virtual environment-specific python and pip executables into your shell's PATH .

How do I add Python path to virtual environment?

Just put a file with a . pth extension (any basename works) in your virtualenv's site-packages folder, e.g. lib\python2. 7\site-packages , with the absolute path to the directory containing your package as its only contents.

How do I activate a virtual environment in Python?

To use the virtual environment you created to run Python scripts, simply invoke Python from the command line in the context where you activated it. For instance, to run a script, just run python myscript.py .

How do I know if my VENV is activated?

Once you can see the name of your virtual environment—in this case (venv) —in your command prompt, then you know that your virtual environment is active. You're all set and ready to install your external packages!


2 Answers

sys.path is initiated in site.py, it is set using the relative path of sys.prefix, which is the path of python executable inside the virtual environment.

assuming you are using virtualenv, rather than -m venv, access to system-wide site-packages is controlled with a flag file named no-global-site-packages.txt, under site dir of the virtual environment.

if the virtual environment is created without option --system-site-packages, a file named no-global-site-packages.txt will be written into the site dir of venv.

during python startup, site.py is executed, it will check the existence of no-global-site-packages.txt, if this flag file not exists, system-wide site package path will be added to sys.path, which is infered from sys.real_prefix. site.py in a virtualenv created venv is a modified version.

hope this could answer your question.

like image 60
georgexsh Avatar answered Sep 17 '22 20:09

georgexsh


The short answer is that activating a virtual environment does not change sys.path. sys.path is determined once Python starts up; see https://docs.python.org/3.7/library/sys.html#sys.path. What the virtual environment does, by adjusting your PATH environment variable, is change what interpreter actually runs when you simply run python.

like image 39
chepner Avatar answered Sep 18 '22 20:09

chepner