Skip to content

User-installed Python modules do not have precedence over those pre-installed in the snap #167

Open

Description

@furgo16

The snap comes with a series of Python modules preinstalled, which on the host system are installed at:

/snap/freecad/current/usr/lib/python3.10/dist-packages/$MODULE

The user can install new Python modules using the provided freecad.pip command. Those modules are then installed at:

$HOME/snap/freecad/common/.local/lib/python3.10/site-packages/$MODULE

Sometimes it is useful for one of the preinstalled Python modules (e.g. ifcopenshell) to be upgraded. Be it to fix a bug, or to use a new feature. This works in principle. E.g.

freecad.pip install ifcopenshell

As expected, we then end up with:

/snap/freecad/current/usr/lib/python3.10/dist-packages/ifcopenshell         # The version we just installed: 0.8.1
$HOME/snap/freecad/common/.local/lib/python3.10/site-packages/ifcopenshell  # The preinstalled version: 0.8.0

If we then import ifcopenshell from the Python console within FreeCAD:

>>> import ifcopenshell
>>> ifcopenshell.__version__
'0.8.0'

Notice how FreeCAD's Python only saw the preinstalled version. When the snap is launched, a message seems to indicate that the user path is searched for before the system path:

Adding snap-specific PYTHONPATH to sys.path: $HOME/snap/freecad/common/.local/lib/python3.10/site-packages:/snap/freecad/1296/lib/python3.10/site-packages:/snap/freecad/1296/usr/lib/python3/dist-packages

pythonpath = os.environ.get("SNAP_PYTHONPATH")
if pythonpath:
print(f"Adding snap-specific PYTHONPATH to sys.path: {pythonpath}")
os.environ["PYTHONPATH"] = pythonpath
for path in pythonpath.split(":"):
sys.path.insert(0, path)

However, that does not seem to be the case.

Running:

>>> import sys
>>> print(sys.path)

Returns PYTHONPATH, of which here's an edited extract:

/snap/freecad/1296/usr/lib/python3/dist-packages
/snap/freecad/1296/lib/python3.10/site-packages
$HOME/freecad/common/.local/lib/python3.10/site-packages
$HOME/freecad/common/.local/lib/python3.10/site-packages  # <= Injected by $SNAP_PYTHONPATH?
/snap/freecad/1296/usr/local/lib/python3.10/dist-packages # <= Injected by $SNAP_PYTHONPATH?
/snap/freecad/1296/usr/lib/python3/dist-packages          # <= Injected by $SNAP_PYTHONPATH?
$HOME/freecad/common/AdditionalPythonPackages/py310
$HOME/freecad/common/AdditionalPythonPackages
$HOME/freecad/common/
$HOME/freecad/common
$/snap/freecad/1296/lib/python3.10/site-packages/ifcopenshell/lib/linux/64bit/python3.10

Notice how /snap/freecad/1296/usr/lib/python3/dist-packages is listed first, instead of $HOME/freecad/common/.local/lib/python3.10/site-packages

Running this snippet from FreeCAD's Python console:

>>> import os
>>> pythonpath = os.environ.get("SNAP_PYTHONPATH")
>>> pythonpath
'$HOME/snap/freecad/common/.local/lib/python3.10/site-packages:/snap/freecad/1296/lib/python3.10/site-packages:/snap/freecad/1296/usr/lib/python3/dist-packages'

That list of paths seems to be injected somewhere in the middle of the PYTHONPATH. Since it's inserted after /snap/freecad/1296/usr/lib/python3/dist-packages, it has no effect. Also note that SNAP_PYTHONPATH is a custom environment variable that we define in snapcraft.yaml:

PYTHONPATH: &pypath $PYTHONUSERBASE/lib/python3.10/site-packages:$SNAP/lib/python3.10/site-packages:$SNAP/usr/lib/python3/dist-packages
SNAP_PYTHONPATH: *pypath

In summary, Python packages are forever pinned to the version preinstalled with the snap.

Activity

  1. furgo16 commented on Feb 17, 2025

    @furgo16
    CollaboratorAuthor

    The FreeCADInit file seems to deal with sys.path initialization.

    I wonder if the dist-packages paths could be removed from sys.path on the snap initialization script. Although if FreeCADInit has not been loaded yet, it might be too early.

    pythonpath = os.environ.get("SNAP_PYTHONPATH")
    if pythonpath:
    print(f"Adding snap-specific PYTHONPATH to sys.path: {pythonpath}")
    os.environ["PYTHONPATH"] = pythonpath
    for path in pythonpath.split(":"):
    sys.path.insert(0, path)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions