Import problem with Python

I have snapcraft like this:

name: lorem # you probably want to 'snapcraft register <name>'
base: core20 # the base snap is the execution environment for this snap
version: '1.1.0' # just for humans, typically '1.2+git' or '1.3.2'
summary: Lorem ipsum
description: |
  Lorem ipsum dolot sit amet

grade: stable # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots

parts:
  lorem:
    source: .
    plugin: python
    requirements: ['requirements.txt']

apps:
  lorem:
    command: bin/main.py

bin/main.py:

#!/usr/bin/env python3

from client.main import main


if __name__ == '__main__':
    main(prog_name="lorem")

client/main.py:

from click import group, version_option

from .command.configure import configure
...


@group()
@version_option("1.1.0")
def main():
    pass

main.add_command(configure)

The directory structure is like this:

I get the following error when running the program after installing the snap:

Traceback (most recent call last): File “/snap/lorem/x1/bin/main.py”, line 3, in from client.main import main File “/snap/lorem/x1/lib/python3.8/site-packages/client/init.py”, line 1, in from .main import main File “/snap/lorem/x1/lib/python3.8/site-packages/client/main.py”, line 4, in from .command.configure import configure ModuleNotFoundError: No module named ‘client.command’

In requirements.txt I have Click package (which works ok because importing classes and function from that package didn’t throw an error). I don’t have Client package (which is my self-made package), but that package should be installed when the snap build installs the package based on setup.py. And I think it is installed given this part in the error:

File “/snap/lorem/x1/lib/python3.8/site-packages/client/init.py”, line 1, in

But I don’t know why that throws that import error, if the client package is installed. The application works if I run this normally (without a snap, simply running the bin/main.py script).

I have also tried adding ‘client’ to requirements, but then the build doesn’t work I can see that in logs:

ERROR: Could not find a version that satisfies the requirement client~=1.1.0 (from versions: none) ERROR: No matching distribution found for client~=1.1.0

Does anyone know why I get this error? Or what is the solution?

This is not a solution but a workaround.

  1. Create executables of your app using PyInstaller
  2. Then use those executables to create the snap.

Most probably PyInstaller will take care of the client package.

Thanks for your answer.

I tried that as well. Unfortunately, I’ve run into a different problem that has to do with Click library, when I created the app with PyInstaller and then used those executables in the snap.

I got this error, after running the app in the snap:

Traceback (most recent call last):
  File "main.py", line 7, in <module>
  File "click/core.py", line 1137, in __call__
  File "click/core.py", line 1043, in main
  File "click/_unicodefun.py", line 100, in _verify_python_env
RuntimeError: Click will abort further execution because Python was configured to use ASCII as encoding for the environment. Consult https://click.palletsprojects.com/unicode-support/ for mitigation steps.

This system supports the C.UTF-8 locale which is recommended. You might be able to resolve your issue by exporting the following environment variables:

    export LC_ALL=C.UTF-8
    export LANG=C.UTF-8

Click discovered that you exported a UTF-8 locale but the locale system could not pick up from it because it does not exist. The exported locale is 'en_GB.UTF-8' but it is not supported.
[5693] Failed to execute script 'main' due to unhandled exception!

After I set the environment variables listed in the error message, the application works. But the user have to manually set those environment variables then and I would like the user to have the application working from the start.

Then create a file named “configure” and then add the environment variables in it.

#!/bin/sh

export LC=C.UTF-8
export LANG=c.UTF-8

exec "$@"

and then use the chmod +x configure to make the file executable and put the executable file under bin/ and then call it before you call the main.py in the command. And it should look something like this.

apps:
  lorem:
    command: bin/configure main.py

It’s a good idea. But I can see a problem.

From the information on this website: https://click.palletsprojects.com/en/8.0.x/unicode-support/ , it looks like the environment variables values need to be different depending on the locale the computer is running on. So on my computer values like these worked:

export LC=C.UTF-8
export LANG=c.UTF-8

but on a different computer the values might need to be different.

Possibly, it’s possible to figure out programmatically what I should set it to, but I think it’s impossible or difficult because if it was easy, then the Click library would do that already. But I will investigate if it’s possible later, when I have some time. If anyone can see some different solution in the meantime, I’m open to hear.

I’m not super savvy on how exactly locales work on Linux, but the extensions / Snapcraft Desktop Helpers do have code that fixes up locales in snaps.

Try adding the Gnome extension to your snap, it should be as easy as adding

apps:
  lorem:
    command: bin/main.py
    extensions: [gnome-3-38]

Issues with modules not found in Python are often the result of needing to set the PYTHONPATH variable, you can set simpler variables directly in the snapcraft.yaml, more complex cases might need wrapper scripts like seen above.

environment:
  PYTHONPATH: $SNAP/path/to/python/modules

Thanks. Problem solved. :grinning:

1 Like