Fighting with venv in Python

I had a brain fart today. I was developing a personal project in Python and I had some library issues that I was trying to wrap my head around. It turns out, I didn’t even have my virtual environment running. I completely forgot.

So then I activated it.

source .venv/bin/activate

Then I thought to myself…

I don’t want to type that out every single damn time.

I’m lazy. I don’t like to type unnecessary things. I switch projects mid-day on multiple occasions at work so there’s a bit of a context switch to deal with. If I have to write automation scripts and aliases now to prevent me from typing even the smallest of words, I’ll take the time to try to solve that.

Context issues

So I did just that. I set aside some time to try to automate things.

I wanted a command I could execute (venv). This command would run a script that creates a virtual environment via python3 -m venv .venv. Then it would run source .venv/bin/activate to start the virtual environment.

Well, every time I ran this script, the directory would be created at the current working directory and the source line ran without error but the virtual environment did not start. The Python interpreter my environment was running was still global at /usr/local/bin/python3. So something is amiss!

After doing a bit of research it turns out that when you want to enter a virtual environment, the virtual environment modifies my shell’s variables. An example of this would be modifying my shell’s variables to point to the correct Python interpreter.

Also, when you run a Bash script, it executes in a different context/subshell. The file and directory changes stuck after the script ran, but the necessary variables I needed for my virtual environment were thrown away as soon as the script finished running.

Solution

I removed the source line from my venv.sh script and just left the script to create the needed files and directories. I would then need to run that source command to enter the virtual environment.

Then I thought: Why don’t I just string the commands together into one alias on my shell? Perfect.

1
2
3
4
5
# aliases.sh
alias venv='$HOME/src/dotfiles/bin/utils/venv.sh && \
    source .venv/bin/activate'

# ... other aliases below here

Running the venv alias would execute the venv.sh then run the source command in the context of the shell I am currently in.

#!/bin/bash
# venv.sh
# create venv if not exists
  if [ -d ".venv" ]; then
    echo "Found .venv. Activating..."
  else
    read -p ".venv does not exist. Would you like to \
         create a venv for this directory? (y/n) " response
    if [ "$response" == "y" ]; then
      echo "Creating .venv directory @ $PWD"
      python3 -m venv .venv
    fi
  fi

If venv.sh finds an existing .venv directory, it does nothing. If the script does not find the .venv directory it prompts the user asking if the script has permission to create it. I know I could probably do without the prompt and just have the script create it. I decided to leave it in for now.

I guess my issue was with Bash and not venv. Anyway, I think I have to be careful. I’ve been getting sidetracked and spending a lot of time configuring my environment. Off to building something!

Be sure to follow me @chrisparaiso.

Built with Hugo
Theme Stack designed by Jimmy