Hi, there’s a similar issue #63912 and a thread on the guix-devel mailinglist at https://lists.gnu.org/archive/html/guix-devel/2023-06/msg00066.html
> So, looks like the default Python behavior is to load the usercustomize > after the sitecustomize [1], which leads to exactly the behavior you're > experiencing. I don't know what we should do here, maybe pass `-s` to > the shebang line of Python to disable loading the usercustomize? That > would probably be a world-rebuild though. CC'ing the Python team to see > what they think. I think the problem is bigger than usercustomize. Any custom PYTHONPATH also slips through and causes this issue, as well as any custom GUIX_PYTHONPATH, because the executable wrapper appends it (think nested `guix shell` invokations with different versions of a library for an example where this could go wrong). Guix-managed Python packages (libraries nor applications) should generally not pick up dependencies from random paths – only those from their package description, so we can keep Guix’ promise of being self-contained. I have experimented with customizing Python’s importing mechanism through a custom MetaPathFinder. It works by adding a __guix_pythonpath__ variable to every Python package’s __init__.py file and modifying the module loader’s search path accordingly if such a variable exists. It would provide exactly that guarantee, but it’s just a PoC at this point – see attached file. Apart from that I don’t see a good short-term solution right now. It’s just how Python works. Cheers, Lars
# Credits to # https://tenthousandmeters.com/blog/python-behind-the-scenes-11-how-the-python-import-system-works/ # for the very good explanation of how Python’s import statement works. import sys, os from importlib.abc import MetaPathFinder from importlib.machinery import SourceFileLoader, ModuleSpec, PathFinder class GuixPythonFinder (MetaPathFinder): def find_spec (self, fullname, path, target=None): # Short-circuit for non-top-level imports, which already have a path. if path: return None attrname = '__guix_pythonpath__' searchPath = None # Search for our caller. frame = sys._getframe () while frame: # If he has a search path, use it. This is mainly for executable # scripts with `__name__ == '__main__'`. searchPath = frame.f_globals.get (attrname, None) if not searchPath: # Otherwise check the top-level package for search paths # declared in __init__.py package = frame.f_globals.get ('__package__') if package: module = sys.modules.get (package) if module: searchPath = getattr (module, attrname, None) if searchPath is not None: break frame = frame.f_back # If we have a caller… if searchPath is not None: return PathFinder.find_spec (fullname, searchPath, target=target) else: # Otherwise we’re not responsible for this module. return None sys.meta_path.insert (0, GuixPythonFinder ())