What goes under the hood of `mkvirtualenv` command?
Asked Answered
S

1

6

I am curious about what happens under the hood of the mkvirtualenv command and so I am trying to understand how it calls virtualenv.

The lowest hanging fruit is to figure where the virtualenv program is located after installation and where the mkvirtualenv program is located after installation. So:-

Calvins-MacBook-Pro.local ttys006 Mon Apr 23 12:31:07 |~|
calvin$ which mkvirtualenv
Calvins-MacBook-Pro.local ttys006 Mon Apr 23 12:31:10 |~|
calvin$ which virtualenv
/opt/local/library/Frameworks/Python.framework/Versions/2.7/bin/virtualenv

So the strange thing I see here is that which mkvirtualenv does not give any result. Why?

Digging further, in the virtualenvwrapper directory after installing it, I see only 3 python files:-

Calvins-MacBook-Pro.local ttys004 Mon Apr 23 12:28:05 |/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/virtualenvwrapper|
calvin$ ls -la
total 88
drwxr-xr-x   8 root  wheel    272 Apr 13 15:07 .
drwxr-xr-x  29 root  wheel    986 Apr 15 00:55 ..
-rw-r--r--   1 root  wheel   5292 Apr 13 15:05 hook_loader.py
-rw-r--r--   1 root  wheel   4810 Apr 13 15:07 hook_loader.pyc
-rw-r--r--   1 root  wheel   1390 Apr 13 15:05 project.py
-rw-r--r--   1 root  wheel   2615 Apr 13 15:07 project.pyc
-rw-r--r--   1 root  wheel   7381 Apr 13 15:05 user_scripts.py
-rw-r--r--   1 root  wheel  11472 Apr 13 15:07 user_scripts.pyc

And I suppose that the only reason why mkvirtualenv is now available in my terminal is because I have added in a source/opt/local/library/Frameworks/Python.framework/Versions/2.7/bin/virtualenvwrapper.sh. So answering the question I asked earlier, this is simply because mkvirtualenv is expressed as a bash function and is available in my terminal because I have sourced virtualenvwrapper.sh in my .bashrc or .bash_profile files.

Digging into the virtualenvwrapper.sh script, I see

# Create a new environment, in the WORKON_HOME.
#
# Usage: mkvirtualenv [options] ENVNAME
# (where the options are passed directly to virtualenv)
#
function mkvirtualenv {
    typeset -a in_args
    typeset -a out_args
    typeset -i i
    typeset tst
    typeset a
    typeset envname
    typeset requirements
    typeset packages

    in_args=( "$@" )

    if [ -n "$ZSH_VERSION" ]
    then
        i=1
        tst="-le"
    else
        i=0
        tst="-lt"
    fi
    while [ $i $tst $# ]
    do
        a="${in_args[$i]}"
        # echo "arg $i : $a"
        case "$a" in
            -a)
                i=$(( $i + 1 ));
                project="${in_args[$i]}";;
            -h)
                mkvirtualenv_help;
                return;;
            -i)
                i=$(( $i + 1 ));
                packages="$packages ${in_args[$i]}";;
            -r)
                i=$(( $i + 1 ));
                requirements="${in_args[$i]}";;
            *)
                if [ ${#out_args} -gt 0 ]
                then
                    out_args=( "${out_args[@]-}" "$a" )
                else
                    out_args=( "$a" )
                fi;;
        esac
        i=$(( $i + 1 ))
    done

    set -- "${out_args[@]}"

    eval "envname=\$$#"
    virtualenvwrapper_verify_workon_home || return 1
    virtualenvwrapper_verify_virtualenv || return 1
    (
        [ -n "$ZSH_VERSION" ] && setopt SH_WORD_SPLIT
        \cd "$WORKON_HOME" &&
        "$VIRTUALENVWRAPPER_VIRTUALENV" $VIRTUALENVWRAPPER_VIRTUALENV_ARGS "$@" &&
        [ -d "$WORKON_HOME/$envname" ] && \
            virtualenvwrapper_run_hook "pre_mkvirtualenv" "$envname"
    )
    typeset RC=$?
    [ $RC -ne 0 ] && return $RC

    # If they passed a help option or got an error from virtualenv,
    # the environment won't exist.  Use that to tell whether
    # we should switch to the environment and run the hook.
    [ ! -d "$WORKON_HOME/$envname" ] && return 0

    # If they gave us a project directory, set it up now
    # so the activate hooks can find it.
    if [ ! -z "$project" ]
    then
        setvirtualenvproject "$WORKON_HOME/$envname" "$project"
    fi

    # Now activate the new environment
    workon "$envname"

    if [ ! -z "$requirements" ]
    then
        pip install -r "$requirements"
    fi

    for a in $packages
    do
        pip install $a
    done

    virtualenvwrapper_run_hook "post_mkvirtualenv"
}

Here's where I don't understand yet - I don't seem to see any direct reference to virtualenv in this bash function. So how exactly does this bash function mkvirtualenv pass the arguments from command line (e.g. mkvirtualenv -p python2.7 --no-site-packages mynewproject) to the python virtualenv program?

Sumptuous answered 23/4, 2012 at 4:54 Comment(0)
S
3

So this is the line that does the trick.

(
    [ -n "$ZSH_VERSION" ] && setopt SH_WORD_SPLIT
    \cd "$WORKON_HOME" &&
    "$VIRTUALENVWRAPPER_VIRTUALENV" $VIRTUALENVWRAPPER_VIRTUALENV_ARGS "$@" &&
    [ -d "$WORKON_HOME/$envname" ] && \
        virtualenvwrapper_run_hook "pre_mkvirtualenv" "$envname"
)

$VIRTUALENVWRAPPER_VIRTUALENV is in fact the location of where the current virtualenv program resides.

In terminal,

Calvins-MacBook-Pro.local ttys004 Mon Apr 23 13:24:14 |~|
calvin$ which $VIRTUALENVWRAPPER_VIRTUALENV
/opt/local/library/Frameworks/Python.framework/Versions/2.7/bin/virtualenv

Mytsery solved.

Sumptuous answered 23/4, 2012 at 5:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.