20

Environment

  • Windows Subsystem for Linux with Serial Communication to a GPS.

  • Adafruit GPS connected to a Arduino Nano which is connected to COM10. In Windows Subsystem for Linux this is equivalent to /dev/ttyS10

  • Requirements: pyserial

I have written a simple script to read information from the GPS module:

import serial

def select_sentence():
""" This function sends serial data to the GPS module to display only GPGGA and GPRMC"""

def read_gps():
    ser = serial.Serial("/dev/ttyS10", 9600)
    while True:
         print(ser.readline().decode('utf-8'))

if __name__ == "__main__":
     select_sentence()
     read_gps()

In the virtualenv I chose Python3 and when I executed it I got Permission Error for the serial port /ttyS10 so I chose to sudo chmod 666 /dev/ttyS10 to use the script in the virtualenv.

However is there an alternative to the above mentioned chmod /dev/serial in order to avoid the PermissionErrors?

I am aware that even in the virtualenv when one uses sudo the packages installed in the virtualenv are no considered and instead sudo looks for your global pip packages.

Shan-Desai
  • 3,101
  • 3
  • 46
  • 89

4 Answers4

26

When you activate a virtualenv (by source venv/bin/activate or similar), that basically just tells your shell: "hey, when you search for a command, look in venv/bin before you look anywhere else", by updating the $PATH environment variable. That way, when you run a command like python, your shell sees and runs the python in venv/bin instead of in /usr/bin or wherever. That copy of Python is configured to look in venv/lib for packages rather than /usr/lib, so you can use the packages in your virtualenv instead of the ones installed globally.

However, when you run a program with sudo, it ignores $PATH. Why does it do that? Because in the historical days of *nix, it was common to have sudo set up so that users could execute only specific commands with it, like (say) sudo iftop1, so that anyone could check what the network was being used for, but still nobody could run sudo rm -rf /*. If sudo respected the user's $PATH, you could just copy /bin/rm to ~/bin/iftop, add ~/bin to your $PATH, then run sudo iftop – but you would actually be running rm as root!

So, sudo ignores $PATH by default. But you can still execute specific programs by giving sudo the full path to the program, so you can execute the Python in your virtualenv as root by running something like sudo ./venv/bin/python (assuming your virtualenv is called venv). That will make you root while still having access to the packages in your virtualenv, like pyserial.

1: I don't actually know of any command that would be set up like this, this is a bad example, sorry.

ash
  • 5,139
  • 2
  • 27
  • 39
2

Also make sure you have created virtualenv without sudo command, since that may cause permissions issues on using virtual env without sudo later. If that's the case run the command below:

sudo chown -R your_username:your_username path/to/virtuaelenv/

Than you can enable permissions for reading the /dev/ttyS10 for your user and run python script by that user.

NOTE: Also you want to add shebang line to to the top of your python script with the path to python interpreter which sits in your env. So you will be able to call it without interpreter.

#!/usr/bin/env python

See more on that SO Answer: Should I put #! (shebang) in Python scripts, and what form should it take?

Andriy Ivaneyko
  • 20,639
  • 6
  • 60
  • 82
  • Instead of `#!/path/to/venv/bin python3` you could also just use `#!/usr/bin/env python` which will automatically use whatever python (or python3) that your venv is configured to use, specifically the one installed in the venv. – Tim S. Feb 28 '20 at 16:36
  • @TimS. Thanks ! That makes complete sense. – Andriy Ivaneyko Feb 28 '20 at 16:58
2

Add alias in your linux machine:

# ~/.bash_aliases

alias spython='sudo $(printenv VIRTUAL_ENV)/bin/python3'

NOTE: make sure you have virtual env activated.

Run python script with spython command :)

spython file.py
JD Solanki
  • 898
  • 8
  • 18
1

Here is my workaround on bash. Put this in an executable file on your PATH (e.g. vesudo):

#!/bin/bash

if [ -z "$VIRTUAL_ENV" ]; then
  echo "Error: Virtual environment not found" >&2
  exit 1
fi

_args=''
for _a in "$@"; do
  _a="${_a//\\/\\\\}"
  _args="$_args \"${_a//\"/\\\"}\""
done

sudo bash <<_EOF
source "$VIRTUAL_ENV/bin/activate"
$_args
_EOF

The logic is simple: Escape input arguments, run a privileged subshell, source virtual environment and pass arguments to the subshell.

Example usage:

~/tmp$ source .venv/bin/activate
(.venv) ~/tmp$ which python
/home/omer/tmp/.venv/bin/python
(.venv) ~/tmp$ vesudo which python
/home/omer/tmp/.venv/bin/python
(.venv) ~/tmp$ which pip
/home/omer/tmp/.venv/bin/pip
(.venv) ~/tmp$ vesudo which pip
/home/omer/tmp/.venv/bin/pip
(.venv) ~/tmp$ vesudo python -c 'import sys; print(sys.argv)' it works 'with spaced arguments' as well
['-c', 'it', 'works', 'with spaced arguments', 'as', 'well']
(.venv) ~/tmp$ vesudo echo '$HOME'
/root

I put this script in a repo for convenience.

ofo
  • 1,160
  • 10
  • 21