I am in the process of developing and building my first snap and I started with the devmode confinement for it and got it working. I then switched it to classic confinement (because the snap requires access to a wide variety of devices under /dev to do its job). However, I get a ModuleNotFoundError exception for the python module of the application being snapped.
Below is the snapcraft.yaml that I have created.
name: glucometerutils
summary: A command-line utility to interact with glucometers.
description: |
This provides a command-line utility to interact with a number of
blood sugar meters (glucometers) models from various manufacturers.
adopt-info: glucometerutils
grade: stable
confinement: classic
base: core20
architectures:
- build-on: [amd64]
run-on: [amd64]
apps:
glucometer:
command: bin/glucometer
plugs:
- block-devices
- hidraw
- raw-input
- raw-usb
- removable-media
- scsi-generic
- serial-port
parts:
glucometerutils:
source: https://github.com/glucometers-tech/glucometerutils.git
override-pull: |
snapcraftctl pull
snapcraftctl set-version "$(git rev-parse HEAD | cut -c -10)"
plugin: python
python-packages:
- attrs
- construct
- crcmod
- freestyle-hid>=1.0.2
- hidapi
- PYSCSI[sgio]>=2.0.1
- pyserial[cp2110]>=3.5b0
The exception that I am getting only with the classic mode build is
Traceback (most recent call last):
File "/snap/glucometerutils/x1/bin/glucometer", line 5, in <module>
from glucometerutils.glucometer import main
ModuleNotFoundError: No module named 'glucometerutils'
I do not see this error when building the snap with devmode confinement. I am not sure if I am missing anything obvious here. Help!
You can stage python3.8-minimal, set a symlink from $SNAPCRAFT_PART_INSTALL/bin/python3 to ../usr/bin/python3.8 in override-build and execute the command with the python interpreter bundled in the snap (by defining the app command as bin/python $SNAP/bin/glucometer). Something like:
@cmatsuoka, thank you for your suggestion. It resolved the issue that I was having.
However, as someone new to the snap ecosystem and building snaps, I am wondering why these manual steps are needed in the first place even when I have explicitly mentioned that I am using the python plugin. The extra packages that you have suggested installing are a part of any typical python installation and I do not understand why they need to be manually installed even though I am explicitly specifying that I am building a part using the python plugin, which, imho, should have transparently taken care of installing and setting up the relevant dependencies?
And why does this issue not pop up when I built and installed the snap in the devmode confinement, but does when I build it in the classic confinement. Do you have any idea?
Is there some documentation/examples that I can read up to understand the issue and the solution better?
I suspect the only change that was required to fix your issue was to add the explicit call to the python executable in the command: entry. Without that you were using the #! on the script you were calling which is likely set to /usr/bin/python or /usr/bin/python3 - both of these will be outside your snap in a classic snap so they will not know about and likely be incompatible with the python modules in your snap.
The python plugin doesn’t know about the classic snap concept – in fact, for core22 part building is handled by a separate library that’s also used by other applications such as Charmcraft. The proposed change runs the snapped Python code using the bundled Python interpreter (as @lucyllewy mentioned) since the host system may have an incompatible version or not have a Python interpreter installed at all. The extra packages are used to add the Python interpreter to the snap. When you execute a snap using non-classic confinement you don’t need to do that because the root filesystem is predictable:
$ sudo snap run --shell word-salad
root@hiccup:/home/claudio# grep NAME /etc/os-release
NAME="Ubuntu Core"
PRETTY_NAME="Ubuntu Core 18"
For other examples you can check Snapcraft itself or Charmcraft, they’re both Python applications that use classic confinement.