Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable snap-specific modified PYTHONPATH #176

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

furgo16
Copy link
Collaborator

@furgo16 furgo16 commented Feb 26, 2025

Summary

Fix Python path search order so that user Python packages have precedence over system Pyton Packages. Enable FreeCAD to use upgraded packages even if an older version is already provided by the system.

Fixes #167

Details

The Python modules search path in FreeCAD is put together on src/App/FreeCADInit.py. There, initially the path (as in sys.path) is set to the standard Python locations adapted to the snap environment:

/snap/freecad/1313/usr/lib/python3/dist-packages
/snap/freecad/1313/lib/python3.10/site-packages
$HOME/snap/freecad/common/.local/lib/python3.10/site-packages

Afterwards, the path for each FreeCAD module is prepended to sys.path:

>>> print(*sys.path, sep='\n')
$HOME/snap/freecad/common/Mod/Launcher
/snap/freecad/1313/usr/Mod/Web
/snap/freecad/1313/usr/Mod/Tux
/snap/freecad/1313/usr/Mod/Test
/snap/freecad/1313/usr/Mod/TechDraw
/snap/freecad/1313/usr/Mod/Surface
/snap/freecad/1313/usr/Mod/Start
/snap/freecad/1313/usr/Mod/Spreadsheet
/snap/freecad/1313/usr/lib/python3/dist-packages              # Added by SnapSetup, masks original PYTHONPATH
/snap/freecad/1313/lib/python3.10/site-packages               # Added by SnapSetup, masks original PYTHONPATH
$HOME/snap/freecad/common/.local/lib/python3.10/site-packages # Added by SnapSetup, masks original PYTHONPATH
/snap/freecad/1313/usr/Mod/SnapSetup
/snap/freecad/1313/usr/Mod/Sketcher
/snap/freecad/1313/usr/Mod/Show
/snap/freecad/1313/usr/Mod/Robot
/snap/freecad/1313/usr/Mod/ReverseEngineering
/snap/freecad/1313/usr/Mod/Points
/snap/freecad/1313/usr/Mod/Plot
/snap/freecad/1313/usr/Mod/PartDesign
/snap/freecad/1313/usr/Mod/Part
/snap/freecad/1313/usr/Mod/OpenSCAD
/snap/freecad/1313/usr/Mod/MeshPart
/snap/freecad/1313/usr/Mod/Mesh
/snap/freecad/1313/usr/Mod/Measure
/snap/freecad/1313/usr/Mod/Material
/snap/freecad/1313/usr/Mod/Inspection
/snap/freecad/1313/usr/Mod/Import
/snap/freecad/1313/usr/Mod/Idf
/snap/freecad/1313/usr/Mod/Help
/snap/freecad/1313/usr/Mod/Fem
/snap/freecad/1313/usr/Mod/Draft
/snap/freecad/1313/usr/Mod/CAM
/snap/freecad/1313/usr/Mod/BIM
/snap/freecad/1313/usr/Mod/Assembly
/snap/freecad/1313/usr/Mod/AddonManager
/snap/freecad/1313/usr/Mod
/snap/freecad/1313/usr/lib
/snap/freecad/1313/usr/Ext
/snap/freecad/1313/usr/bin
/snap/freecad/1313/usr/lib/python310.zip
/snap/freecad/1313/usr/lib/python3.10
/snap/freecad/1313/usr/lib/python3.10/lib-dynload
$HOME/snap/freecad/common/.local/lib/python3.10/site-packages # Original snap-specific PYTHONPATH
/snap/freecad/1313/usr/local/lib/python3.10/dist-packages     # Original snap-specific PYTHONPATH
/snap/freecad/1313/usr/lib/python3/dist-packages              # Original snap-specific PYTHONPATH
$HOME/snap/freecad/common/
$HOME/snap/freecad/common
/snap/freecad/1313/usr/Macro

Peculiarities:

  • The FreeCADInit.py file is converted to a C++ header (FreeCADInit.h) at build time, which is included in src/App/Application.cpp
  • The list of modules to search for is added in reverse alphabetical order. I don't know if there is a specific reason for this.

The snap has a mechanism for injecting initialization Python code by adding it to the SnapSetup/Init.py file. As that file is installed on the Mod directory, it will be loaded by FreeCADInit.py as any other regular module.

One of the things that SnapSetup/Init.py does is to initialize the snap-specific PYTHONPATH. There are two issues with this:

  1. The snap-specific PYTHONPATH was already initialized. Probably somewhere before FreeCADInit.py was executed.
  2. SnapSetup/Init.py adds each path entry defined in its SNAP_PYTHONPATH list in reverse order into sys.path

Point 2 is the actual issue. Since it reverses the original search path and it appears before it in sys.path (point 1), it effectively changes the search order. The search order becomes: system paths first (/snap/freecad/1313/usr/local/lib/python3.10/dist-packages) then user paths ($HOME/snap/freecad/common/.local/lib/python3.10/site-packages).

This means that the user can install a newer version of a package via pip, yet that newer version will not be used if there is an older version of the package installed in a system location (e.g. a dependency shipped by FreeCAD, such as ifcopenshell). Python will never see the newer version, as it will search the system location, find the package and load it from there.

There seems to have been much care put in setting this up in snapcraft.yaml. So I'm not sure it's an oversight (a bug), or something that used to work in the past and it no longer does. The reverse insertion order at least seems deliberate.

As such, I'd rather not remove the code, but just uncomment it for now, with a reference to this PR for more info. In case it turns out that deactivating it is causing issues.

In summary, this PR deactivates setting the snap-specific PYTHONPATH on startup, as there is no need to modify the already correct PYTHONPATH being set before.

@furgo16 furgo16 marked this pull request as ready for review February 26, 2025 04:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

User-installed Python modules do not have precedence over those pre-installed in the snap
1 participant