how to deploy unique Python venvs per user?


I have a Mac lab running Catalina and Python 3.x (multiple versions) from, not Apple's built-in Python.
We would like to deploy Python virtual environments as follows— the first 2 are easy enough but I'm stuck on #3:

  • one shared standard user account per course (cs100, cs110 cs120, etc)
  • each user account has its own Python virtual env in its home directory
  • each user account has its $PATH set so that when the user types python3 in, it invokes the appropriate python executable from the virtual env in that user's home directory (eg /Users/cs100/my/venv/bin/python3) 
  • this should work in both bash and zsh
  • we would like the activation of the virtual env to be automatic and invisible to the user — these are intro-level students and the goal is to get their hands on Python with minimal setup

Additionally, we'll need a script to return the user space to clean state at login, but that shouldn't be hard.



not surprisingly, the hard part was easy and the easy part is hard.

I’ve got the Python virtualenvs under control. Now I’m fighting with a bash script to reset the user home to a clean state on login.

This script runs fine when I run it as one of the shared-account users (eg “cs_111”), but when I try to run it as a LaunchAgent upon user login, I get permission errors and the rsync command fails every time.

Here’s the script:



## variable setup
## set the userList
## who's logging in?

## create the courses group if it doesn't already exist

groupExists=$(dscl . list /Groups | grep cs_courses) ;
if test -z "$groupExists"
echo "group does not exist; creating group"
/usr/bin/dscl . -create /Groups/cs_courses
/usr/bin/dscl . -append /Groups/cs_courses RealName 'CS_course_accounts'
echo "group already exists"

## get all CS Course Account usernames & dump to text file

/usr/bin/dscl . -list /Users | grep cs_ > "$userList" ;

## add all CS Course Account users to group

while read thisUser; do
/usr/bin/dscl . -append /Groups/cs_courses GroupMembership "$thisUser" ;
done < "$userList" ;

# who's logging in and are they in 'courses' group?
if grep -q "$theUser" "$userList" ; then

## nuke the userspace & create clean from user template
/usr/local/bin/rsync -rltvh --delete --force --ignore-errors '/Library/User Template/Non_localized'/* /Users/"$theUser"/
## copy any specific per-user items
/usr/local/bin/rsync -rltvh /Library/CS_lab_items/"$theUser"/* /Users/"$theUser"/