Can't get python module "gymnasium" to work in venv using FHS

I’m trying to use the python module gymnasium. I’m using a venv that runs inside a FHS created using:

{
  pkgs ? import <nixpkgs> { },
}:

(pkgs.buildFHSUserEnv {
  name = "python-fhs-env";
  targetPkgs = pkgs: [
    pkgs.python3
    pkgs.gcc
    pkgs.glibc
    pkgs.zlib
    pkgs.libGL
    pkgs.glib
    pkgs.qt5.qtbase
    pkgs.libsForQt5.qt5.qtwayland
    pkgs.SDL2
    pkgs.SDL2.dev
    pkgs.xorg.libX11
    pkgs.xorg.libX11.dev
  ];
  runScript = ''zsh'';
  profile = ''
    source ~/tu/env/bin/activate
    export PATH=${pkgs.SDL2.dev}/bin:$PATH
  '';
}).env

Inside the FHS i’ve created a python environment with python -m venv env.
Then i installed gymnasium with pip install gymnasium[atari] .

Now i’m trying to use the module:

import gymnasium as gym
import ale_py

env = gym.make('ALE/Breakout-v5', render_mode="human")

Note that i’m using render_mode=“human” which uses SDL2 to visually render the game.

I’m getting the following error:

Traceback (most recent call last):
  File "/home/raphael/fun/offline-rl/main.py", line 4, in <module>
    env = gym.make('ALE/Breakout-v5', render_mode="human")
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/raphael/tu/env/lib/python3.12/site-packages/gymnasium/envs/registration.py", line 740, in make
    env = env_creator(**env_spec_kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/raphael/tu/env/lib/python3.12/site-packages/ale_py/env.py", line 159, in __init__
    self.load_game()
  File "/home/raphael/tu/env/lib/python3.12/site-packages/ale_py/env.py", line 216, in load_game
    self.ale.loadROM(roms.get_rom_path(self._game))
RuntimeError: Failed to initialize SDL

This doesn’t give much information so I’ve tried to use pygame which also uses SDL2 and provides additional information:

import pygame

pygame.init()
screen = pygame.display.set_mode((400, 300))
print("Available display drivers:", pygame.display.get_driver())

output:
Available display drivers: offscreen

This is odd, i would have expected wayland (which is what i’m running) or x11 (i could use that with xwayland).
I’ve tried to make it use x11 using SDL_VIDEODRIVER=x11 python <script.py> this results in:
pygame.error: x11 not available . Or with wayland in wayland not available.

I thought i would try to use sdl2 directly using PySDL2:

import sdl2

sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)

num_drivers = sdl2.SDL_GetNumVideoDrivers()
print(f"Number of available video drivers: {num_drivers}")

print("Available video drivers:")
for i in range(num_drivers):
    driver_name = sdl2.SDL_GetVideoDriver(i).decode("utf-8")
    print(f"- {driver_name}")

output:

Number of available video drivers: 5
Available video drivers:
- x11
- wayland
- offscreen
- dummy
- evdev

so here the video drivers are detected. I was also able to render something.

strace -e openat python <sdl2-script.py> 2>&1 | grep libSDL2 reveals the reason for this:

openat(AT_FDCWD, "/usr/lib/libSDL2.so", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/nix/store/lw7psn749bfn2nrn943jdh68hh2im8yl-libffi-3.4.6/lib/libSDL2-2.0.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/nix/store/wn7v2vhyyyi6clcyn0s9ixvl7d4d87ic-glibc-2.40-36/lib/libSDL2-2.0.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/nix/store/ybjcla5bhj8g1y84998pn4a2drfxybkv-gcc-13.3.0-lib/lib/libSDL2-2.0.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/libSDL2-2.0.so.0", O_RDONLY|O_CLOEXEC) = 3

So it calls the sdl implementation provided by the FHS. Meanwhile running strace on the initial gymnasium env.make example shows:

openat(AT_FDCWD, "/home/raphael/tu/env/lib/python3.12/site-packages/ale_py/glibc-hwcaps/x86-64-v3/libSDL2-2.0.so.0.16.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/raphael/tu/env/lib/python3.12/site-packages/ale_py/glibc-hwcaps/x86-64-v2/libSDL2-2.0.so.0.16.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/raphael/tu/env/lib/python3.12/site-packages/ale_py/libSDL2-2.0.so.0.16.0", O_RDONLY|O_CLOEXEC) = 3

So its running the libSDL2 provided by the venv.
Running ldd on both sdl2 implementations shows that the venv sdl2lib is not linked against x11:

ldd /lib/libSDL2-2.0.so.0                                                                               
linux-vdso.so.1 (0x00007ffe8552a000)
libm.so.6 => /nix/store/wn7v2vhyyyi6clcyn0s9ixvl7d4d87ic-glibc-2.40-36/lib/libm.so.6 (0x00007f031cf8e000)
libX11.so.6 => /nix/store/ikjw6a952jd9wn5k06mkj710xzabssr0-libX11-1.8.10/lib/libX11.so.6 (0x00007f031cab4000)
libXext.so.6 => /nix/store/d5y0sl4vwsb9m99r18zh1mx4fw9y70g6-libXext-1.3.6/lib/libXext.so.6 (0x00007f031cf77000)
libXcursor.so.1 => /nix/store/622maagcm5lmh4g21y0ks10zgrkjwq4y-libXcursor-1.2.2/lib/libXcursor.so.1 (0x00007f031cf6a000)
libXi.so.6 => /nix/store/mcr8zrlyg2r6idl6ks60858q5q0i6i2a-libXi-1.8.2/lib/libXi.so.6 (0x00007f031cf56000)
libXfixes.so.3 => /nix/store/7glyd73k29s3fk9nksi0brklyyzgg7sq-libXfixes-6.0.1/lib/libXfixes.so.3 (0x00007f031cf4e000)
libXrandr.so.2 => /nix/store/1741axgq503c1r4bzwy1ysp847rsfrf0-libXrandr-1.5.4/lib/libXrandr.so.2 (0x00007f031cf3f000)
libXss.so.1 => /nix/store/6xgaalbp7r3h4hy9fi7qm73gl4g38p2l-libXScrnSaver-1.2.4/lib/libXss.so.1 (0x00007f031cf3a000)
libpthread.so.0 => /nix/store/wn7v2vhyyyi6clcyn0s9ixvl7d4d87ic-glibc-2.40-36/lib/libpthread.so.0 (0x00007f031cf35000)
libc.so.6 => /nix/store/wn7v2vhyyyi6clcyn0s9ixvl7d4d87ic-glibc-2.40-36/lib/libc.so.6 (0x00007f031c8bb000)
/nix/store/wn7v2vhyyyi6clcyn0s9ixvl7d4d87ic-glibc-2.40-36/lib64/ld-linux-x86-64.so.2 (0x00007f031d077000)
libxcb.so.1 => /nix/store/w63ks7mg1dsgm2gg302ss70wpq7g0l4d-libxcb-1.17.0/lib/libxcb.so.1 (0x00007f031cf09000)
libXrender.so.1 => /nix/store/7ygszkkili3kfqh789ivdgrhyrjshm5n-libXrender-0.9.11/lib/libXrender.so.1 (0x00007f031cefa000)
libXau.so.6 => /nix/store/ighb6h0x1nv14ap2fj0j3bqdn0x3xra4-libXau-1.0.11/lib/libXau.so.6 (0x00007f031cef5000)
libXdmcp.so.6 => /nix/store/8jqc1bpk99jgib12wgpdjmnbndrmg7vz-libXdmcp-1.1.5/lib/libXdmcp.so.6 (0x00007f031ceed000)
 ldd /home/raphael/tu/env/lib/python3.12/site-packages/ale_py/libSDL2-2.0.so.0.16.0                     
linux-vdso.so.1 (0x00007fff7663f000)
libm.so.6 => /lib/libm.so.6 (0x00007f69d393d000)
libdl.so.2 => /lib/libdl.so.2 (0x00007f69d3938000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00007f69d3933000)
libc.so.6 => /lib/libc.so.6 (0x00007f69d373a000)
/nix/store/wn7v2vhyyyi6clcyn0s9ixvl7d4d87ic-glibc-2.40-36/lib64/ld-linux-x86-64.so.2 (0x00007f69d3bad000)

This leaves me very confused. If the pip ale_py libSDL2 library is not compiled against x11 or wayland, why does it work on every other linux distribution that i have used it on (inside a venv).

Am i doing anything wrong when creating the FHS?

I’m unsure if the issue is even nixos-related but appreciate any help.

I managed to get it to work with x11 backend (via xwayland) by adding the following packages to my FHS shell:
pkgs.xorg.libX11
pkgs.xorg.libX11.dev
pkgs.xorg.libXext
pkgs.xorg.libXext.dev
pkgs.xorg.libXrandr
pkgs.xorg.libXrandr.dev

I guess those libs are dynamically loaded so ldd doesn’t show them as linked which confused me. I did not get wayland to work though. But strace isn’t even showing any attempt of loading any wayland library so maybe gymnasium or any dependency of gymnasium doesn’t support wayland…