0

I'm trying to daemonise a python script using systemd, but constantly get the error "No module named 'oandapyV20'" after activating the daemon.

The script is at location: /home/user/workingdir/script.py

The virtual environment is at: /home/user/venv/bin/

My best guess at how to build the service from docs I've found is as follows:

[Unit]
Description=DataLoader
[Service]
User=root
Group=root
WorkingDirectory=/home/user/workingdir
ExecStart=/home/user/venv/bin/python3 script.py
[Install]
WantedBy=multi-user.target

What does work...

python3 script.py

or activating virutal environment

source /home/user/venv/bin/activate; python3 script.py

Although that works outside of the service, nothing I've tried works when calling from systemd.

Where am I going wrong? What am I not realising?

Eventual solution (with little understanding)

[Unit]
Description=DataLoader
[Service]
User={user_name}
Group={user_name}
WorkingDirectory=/home/{user_name}/workingdir
ExecStart=/usr/bin/python3 script.py
Restart=always
[Install]
WantedBy=multi-user.target
7
  • What happens if you become root with sudo su - (with hyphen) and execute cd /home/user/workingdir; /home/user/venv/bin/python3 script.py? Is it different with sudo su (no hyphen)? If so, I'd scrutinize differences in environment variables. You might also run source /home/user/venv/bin/activate; which python3 to make sure you're actually calling /home/user/venv/bin/python3 as you currently believe. – gnubeard Apr 1 '20 at 20:56
  • @gnubeard thanks for your comment. After logging in as route cd /home/user/workingdir; /home/user/venv/bin/python3 script.py fails with the same module not recognised error. I installed the module whilst logged in as root, but it still fails with same error. I'm missing some fundamental concept about linux or python, why would the module not be available when root? What should I read up on? I'll work on the rest of your suggestions next. – goose Apr 1 '20 at 21:14
  • That indicates that there's something different between your environment and root's environment. Use the env command to print all environment variables, and use source /home/user/venv/bin/activate; which python3 to ensure the python3 you're calling is the python3 you think you're calling. If it's calling a different python3, I'd especially inspect differences in $PATH. – gnubeard Apr 1 '20 at 21:26
  • @gnubeard /home/user/venv/bin/activate; which python3 outputs /usr/bin/python3, don't yet understand why it's not using the virtual evironment. – goose Apr 2 '20 at 11:56
  • That means that when you call source /home/user/venv/bin/activate, it's not setting your $PATH or ($PYTHONPATH) (at least not to what you had thought.) Hopefully that goes a long way toward explaining the discrepancy. – gnubeard Apr 2 '20 at 12:25
2

It appears that you have been operating under the assumption that whenever you called source /home/user/venv/activate, the python3 command (and the pip3 command) would subsequently call the relevant executable from /home/user/venv/bin.

However, the clarification you added in the comments indicates that assumption was incorrect. You hadn't been calling the python from your virtual environment when running script.py; you had been calling the python in /usr/bin (and its corresponding pip too, it seems, since the python in your virtualenv doesn't seem to have the oandapyV20 module installed, while the system python does.)

Examine the output of

echo $PATH
echo $PYTHONPATH

The $PATH environment variable is a colon-separated list of paths on your system to be searched when you enter a command. Either /home/user/venv/bin is not present in that list or it occurs after an occurrence of /usr/bin, which contains a match for python3 ($PATH will stop being scanned after the first match.) $PATH is usually set by $HOME/.bashrc (or /etc/bashrc if not set there) and if your assumption had been correct, /home/user/venv/activate would have been setting $PATH to prepend /home/user/venv/bin to it.

$PYTHONPATH should tell python where to look for modules to load. (It can also be modified or read from your script with sys.path.)

That explains why changing your systemd unit's command worked-- it's finally calling the same python that your working command did.

1
  • Thanks gnubeard, I really appreciated the help. This one's taken some time to get to the bottom of. I'm really keen on understanding linux more, but can't really see where to start. Pls feel free to recommend any good resources that helped you learn it. – goose Apr 2 '20 at 13:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.