How to run a Python script using its specific virtual environment without first activating it.

If you find yourself wanting to use your Python app as if it were the same as any other shell command, need to run Python code from within a shell script, or perhaps call it on a schedule from a cron job, it isn't immediately obvious how to get your Python code to use the virtual environment (venv) it needs. Typically running Python inside a virtual environment requires you to "activate" the virtual environment.

I've seen variations on this problem asked a few times, but I haven't seen this technique widely used and it's so simple I don't know why it's not more widely known.

The trick is knowing that when you run the python interpreter from inside the virtual environment bin directory rather than the system Python interpreter, it will have the correct paths available to import modules inside the venv without activating it first. So, instead of running your code using:

  $ . ./<my_virtual_environment>/bin/activate
  $ python <my_script>.py

You can run the script (without sourcing the activate command) like this:

  $ ./<my_virtual_environment>/bin/python <my_script>.py

To make this even easier, I create a shell script with the same name as the python script, but without the .py extension, make it executable (chmod +x <my_script>) and put the following in it:

  #!/usr/bin/env sh
  "exec" "`dirname $0`/<my_virtual_environment>/bin/python" "`dirname $0`/`basename $0`.py" "$@"

If you add the folder containing your python code to your path, then calling <my_script> from anywhere will run your python code using the correct virtual environment just as if it is any other shell command on your system! It also has the benefit of passing any command line arguments straight through to your Python code.