Movatterモバイル変換


[0]ホーム

URL:


Skip to main content
Adafruit Logo
0

Python Virtual Environment Usage on Raspberry Pi

published October 24, 2023, last edited March 08, 2024
Save Link Note Download
43
Intermediate
Project guide

Usage With sudo

Now things are getting more Raspberry Pi specific. Sometimes elevated privileges are needed to access certain hardware on the Raspberry Pi (ex: /dev/mem). The typical way to do this is by invoking the Python script using sudo. However,sudo usage with virtual environments requires some special attention.

It's not as simple assudo make me a sandwich.

NeoPixel Example

Let's use a simple NeoPixel script as an example, since NeoPixels generally require running with sudo. Here's the simple NeoPixel code we want to run, which we will callneo_test.py:

import boardimport neopixelpixels = neopixel.NeoPixel(board.D18, 10)pixels.fill(0xADAF00)
import boardimport neopixelpixels = neopixel.NeoPixel(board.D18, 10)pixels.fill(0xADAF00)

We start with a Raspberry Pi setup with Blinka:

For this example, Blinka is installed into a venv called blinka (remember venv names are just names) using themanual process.

pi@raspberrypi:~ $ python3 -m venv blinka(blinka) pi@raspberrypi:~ $ source blinka/bin/activate(blinka) pi@raspberrypi:~ $ pip3 install --upgrade adafruit-blinka
pi@raspberrypi:~ $ python3 -m venv blinka(blinka) pi@raspberrypi:~ $ source blinka/bin/activate(blinka) pi@raspberrypi:~ $ pip3 install --upgrade adafruit-blinka

And then the NeoPixel library is also installed:

(blinka) pi@raspberrypi:~ $ pip3 install adafruit-circuitpython-neopixel
(blinka) pi@raspberrypi:~ $ pip3 install adafruit-circuitpython-neopixel

If we try runningneo_test.py without sudo, we get a permission error:

(blinka) pi@raspberrypi:~ $ python3 neo_test.py Can't open /dev/mem: Permission deniedTraceback (most recent call last):  File "/home/pi/neo_test.py", line 6, in <module>    pixels.fill(0xADAF00)  File "/home/pi/blinka/lib/python3.11/site-packages/adafruit_pixelbuf.py", line 216, in fill    self.show()  File "/home/pi/blinka/lib/python3.11/site-packages/adafruit_pixelbuf.py", line 204, in show    return self._transmit(self._post_brightness_buffer)           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  File "/home/pi/blinka/lib/python3.11/site-packages/neopixel.py", line 180, in _transmit    neopixel_write(self.pin, buffer)  File "/home/pi/blinka/lib/python3.11/site-packages/neopixel_write.py", line 42, in neopixel_write    return _neopixel.neopixel_write(gpio, buf)           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  File "/home/pi/blinka/lib/python3.11/site-packages/adafruit_blinka/microcontroller/bcm283x/neopixel.py", line 78, in neopixel_write    raise RuntimeError(RuntimeError: NeoPixel support requires running with sudo, please try again!swig/python detected a memory leak of type 'ws2811_t *', no destructor found.(blinka) pi@raspberrypi:~ $
(blinka) pi@raspberrypi:~ $ python3 neo_test.py Can't open /dev/mem: Permission deniedTraceback (most recent call last):  File "/home/pi/neo_test.py", line 6, in <module>    pixels.fill(0xADAF00)  File "/home/pi/blinka/lib/python3.11/site-packages/adafruit_pixelbuf.py", line 216, in fill    self.show()  File "/home/pi/blinka/lib/python3.11/site-packages/adafruit_pixelbuf.py", line 204, in show    return self._transmit(self._post_brightness_buffer)           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  File "/home/pi/blinka/lib/python3.11/site-packages/neopixel.py", line 180, in _transmit    neopixel_write(self.pin, buffer)  File "/home/pi/blinka/lib/python3.11/site-packages/neopixel_write.py", line 42, in neopixel_write    return _neopixel.neopixel_write(gpio, buf)           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  File "/home/pi/blinka/lib/python3.11/site-packages/adafruit_blinka/microcontroller/bcm283x/neopixel.py", line 78, in neopixel_write    raise RuntimeError(RuntimeError: NeoPixel support requires running with sudo, please try again!swig/python detected a memory leak of type 'ws2811_t *', no destructor found.(blinka) pi@raspberrypi:~ $

The error message says to run with sudo, so let's try that:

(blinka) pi@raspberrypi:~ $ sudo python3 neo_test.py Traceback (most recent call last):  File "/home/pi/neo_test.py", line 1, in <module>    import boardModuleNotFoundError: No module named 'board'(blinka) pi@raspberrypi:~ $
(blinka) pi@raspberrypi:~ $ sudo python3 neo_test.py Traceback (most recent call last):  File "/home/pi/neo_test.py", line 1, in <module>    import boardModuleNotFoundError: No module named 'board'(blinka) pi@raspberrypi:~ $

That just throws a different error. And it is confusing. Now it can't find board? What's going on?

The general issue is that sudo launches a new environment when invoked. So the script is running in that new environment, which generally does not known about the virtual environment. That's why the board module (which is part of Blinka installed in the venv) can not be found.

So how do we get around this?

Option 1 - Invoke with sudo passing environment

Thesudo command has the appealing-E option which allows users to "preserve the existing environment variables". Since most of the magic with a venv comes from its altering of thePATH environment variable, it seems like this should work. But it doesn't:

(blinka) pi@raspberrypi:~ $ sudo -E python3 neo_test.pyTraceback (most recent call last):  File "/home/pi/neo_test.py", line 1, in <module>    import boardModuleNotFoundError: No module named 'board'(blinka) pi@raspberrypi:~ $
(blinka) pi@raspberrypi:~ $ sudo -E python3 neo_test.pyTraceback (most recent call last):  File "/home/pi/neo_test.py", line 1, in <module>    import boardModuleNotFoundError: No module named 'board'(blinka) pi@raspberrypi:~ $

The-E did not preserve everything. As a result, the system level Python install ends up being used:

(blinka) pi@raspberrypi:~ $ sudo which python3/usr/bin/python3(blinka) pi@raspberrypi:~ $ sudo -E which python3/usr/bin/python3
(blinka) pi@raspberrypi:~ $ sudo which python3/usr/bin/python3(blinka) pi@raspberrypi:~ $ sudo -E which python3/usr/bin/python3

To get around this, theenv command can be use inline to allow specifying thePATH variable be explicitly copied into the invoking environment:

(blinka) pi@raspberrypi:~ $ sudo -E env PATH=$PATH which python3/home/pi/blinka/bin/python3
(blinka) pi@raspberrypi:~ $ sudo -E env PATH=$PATH which python3/home/pi/blinka/bin/python3

Now it's finding the Python in the venv path. Using this to run the script works:

(blinka) pi@raspberrypi:~ $ sudo -E env PATH=$PATH python3 neo_test.py(blinka) pi@raspberrypi:~ $
(blinka) pi@raspberrypi:~ $ sudo -E env PATH=$PATH python3 neo_test.py(blinka) pi@raspberrypi:~ $

Make an Alias

The commandsudo -E env PATH=$PATH python3 is a bit klunky. To make invoking this easier, an alias can be used.

alias supy='sudo -E env PATH=$PATH python3'
alias supy='sudo -E env PATH=$PATH python3'

The namesupy can be changed to whatever you want. Adding it to.bashrc or.bashrc_aliases will make the alias available with every login. Once the alias is set, can then use it:

(blinka) pi@raspberrypi:~ $ supy neo_test.py
(blinka) pi@raspberrypi:~ $ supy neo_test.py

Option 2 - Use absolute paths

As mentioned previously, a venv can be usedwithout activating by usingabsolute paths to point to the venv's Python install. This also works with sudo.

An easy way to get the absolute path is to activate the venv and check that way:

pi@raspberrypi:~ $ source blinka/bin/activate(blinka) pi@raspberrypi:~ $ which python3/home/pi/blinka/bin/python3
pi@raspberrypi:~ $ source blinka/bin/activate(blinka) pi@raspberrypi:~ $ which python3/home/pi/blinka/bin/python3

And then all that is needed is to invoke with sudo using that absolute path. To demonstrate, firstdeactivate the venv:

(blinka) pi@raspberrypi:~ $ deactivatepi@raspberrypi:~ $
(blinka) pi@raspberrypi:~ $ deactivatepi@raspberrypi:~ $

Now use sudo and the absolute path,no extra parameters are needed:

pi@raspberrypi:~ $ sudo /home/pi/blinka/bin/python3 neo_test.pypi@raspberrypi:~ $
pi@raspberrypi:~ $ sudo /home/pi/blinka/bin/python3 neo_test.pypi@raspberrypi:~ $

Make an Alias

An alias can be made for this as well:

alias supy='sudo /home/pi/blinka/bin/python3'
alias supy='sudo /home/pi/blinka/bin/python3'

Keep in mind the virtual environment is baked into the absolute path. So this command invokes with that specific virtual environment.

But once set, the alias can be used:

pi@raspberrypi:~ $ supy neo_test.pypi@raspberrypi:~ $
pi@raspberrypi:~ $ supy neo_test.pypi@raspberrypi:~ $

Note that the virtual environment is not active in the above example.

Page last edited March 08, 2024

Text editor powered bytinymce.

Related Guides
Search

Search

Categories

[8]ページ先頭

©2009-2025 Movatter.jp