ModuleNotFoundError: No module named 'gi'

I am trying to package this package.
Building it with the following file :

Build file
{ lib
, stdenv
, pkgs
, python3
, python3Packages
, wrapGAppsHook
, pango
, json-glib
, gtk3
, glib
, gobject-introspection
}:

python3Packages.buildPythonApplication rec {
  version = "0.2.4";
  pname = "bottles";
  name = "${pname}-${version}";
  src = pkgs.fetchFromGitHub {
    owner = "mirkobrombin";
    repo = "Bottles";
    rev = "${version}";
    sha256 = "05mf6dxnbnnmw92ir0bskslafjj9nakmjnkqipsaijpj945v399s";
  };
  buildInputs = with pkgs; [ gtk3 python3 glib ];
  nativeBuildInputs =  [
    gtk3
    glib
    wrapGAppsHook
    gobject-introspection
  ];
  propagatedBuildInputs = [
    (pkgs.python3.withPackages (p: with p; [
      pygobject3 gst-python
    ]))
  ];
  doCheck=false;
  patchPhase = ''
    substituteInPlace setup.py --replace /usr/share $out/usr/share
    substituteInPlace bottles/window.py --replace /usr/share $out/usr/share
    substituteInPlace com.github.mirkobrombin.bottles --replace /usr/share/ $out/usr/share/
  '';
  installPhase = ''
    mkdir -p $out/usr
    cp -r bottles data setup.py com.github.mirkobrombin.bottles $out
    python3 $out/setup.py install --prefix "$out/usr"
  '';
}

I get the following error :

Output of the shell
Traceback (most recent call last):
  File "./result/usr/bin/com.github.mirkobrombin.bottles", line 28, in <module>
    import main
  File "/nix/store/1jvyxxj2l7szbchc8nsn9a5j3cn1g7xy-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/main.py", line 22, in <module>
    import gi
ModuleNotFoundError: No module named 'gi'

Would you have any idea why the propagatedBuildInputs are not kicking in ?

    (pkgs.python3.withPackages (p: with p; [
      pygobject3 gst-python
    ]))
  1. Usually, we put these without the whole withPackages thing.
  2. Since you use buildPythonApplication and wrapGAppsHook, you should use in a postInstall or preFixup (untested):
makeWrapperArgs+=("''${gappsWrapperArgs[@]}")

This is in order to spare double wrapping, (EDIT) also:

  dontWrapGApps = true;
  1. Don’t put the same dependencies in both nativeBuildInputs and buildInputs - in your case, only wrapGAppsHook should stay in nativeBuildInputs.
  2. Maybe that error will go away if you’ll put gobject-introspection in buildInputs.
  1. Yeah, buildPythonApplication expects the python packages in propagatedBuildInputs, not python environment that python.withPackages.
  2. buildPythonApplication enables strict deps which breaks the hook: setup hook of gobject-introspection in nativeBuildInputs does not run with strictDeps · Issue #56943 · NixOS/nixpkgs · GitHub

Thank you both for your answers @doronbehar, @jtojnar !
I tried to apply both your comments but with little success : I get the same error while running nix-build -E "with import <nixpkgs> {}; callPackage pkgs/bottles.nix {}" -K --quiet && ./result/usr/bin/com.github.mirkobrombin.bottles

Ouput of the command
Traceback (most recent call last):
  File "./result/usr/bin/com.github.mirkobrombin.bottles", line 28, in <module>
    import main
  File "/nix/store/mywi04zn7plsv2nj6zjcg3bi9z543lc0-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/main.py", line 22, in <module>
    import gi
ModuleNotFoundError: No module named 'gi'

I tried both postInstall and preFixup without any effect.

Here is the file I used modified with your comments :

Build file
{ lib
, stdenv
, pkgs
, python3
, python3Packages
, wrapGAppsHook
, gtk3
, glib
, gobject-introspection
}:

python3Packages.buildPythonApplication rec {
  version = "0.2.4";
  pname = "bottles";
  name = "${pname}-${version}";
  src = pkgs.fetchFromGitHub {
    owner = "mirkobrombin";
    repo = "Bottles";
    rev = "${version}";
    sha256 = "05mf6dxnbnnmw92ir0bskslafjj9nakmjnkqipsaijpj945v399s";
  };
  buildInputs = with pkgs; [ gtk3 python3 glib gobject-introspection ];
  nativeBuildInputs = [ wrapGAppsHook ];
  propagatedBuildInputs = with pkgs.python37Packages; [
      pygobject3
      gst-python
    ];
  doCheck = false;
  dontWrapGApps = true;
  patchPhase = ''
    substituteInPlace setup.py --replace /usr/share $out/usr/share
    substituteInPlace bottles/window.py --replace /usr/share $out/usr/share
    substituteInPlace com.github.mirkobrombin.bottles --replace /usr/share/ $out/usr/share/
  '';
  installPhase = ''
    mkdir -p $out/usr
    cp -r bottles data setup.py com.github.mirkobrombin.bottles $out
    python3 $out/setup.py install --prefix "$out/usr"
  '';
  preInstall = ''
    makeWrapperArgs+=("''${gappsWrapperArgs[@]}")
  '';
}

Prefix should probably be $out, not $out/usr, judging from also from your result/usr/bin/`. That would explain why no wrappers were created.

Good catch @FRidh Interestingly it builds now but it pushed back the problem to runtime ones: running the program now yields

command com.github.mirkobrombin.bottles output
** (.com.github.mirkobrombin.bottles-wrapped:13817): WARNING **: 15:57:16.209: Failed to load shared library '/build/source/build/lib/libgranite.so.5.2.3' referenced by the typelib: /build/source/build/lib/libgranite.so.5.2.3: cannot open shared object file: No such file or directory
/nix/store/kkp78b1wxdzi1iizmbxpw7gf3nr1g1c1-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/welcome.py:49: Warning: cannot retrieve class for invalid (unclassed) type 'void'
  self.welcome = Granite.WidgetsWelcome()
Traceback (most recent call last):
  File "/nix/store/kkp78b1wxdzi1iizmbxpw7gf3nr1g1c1-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/main.py", line 59, in do_activate
    self.win = wn.Window()
  File "/nix/store/kkp78b1wxdzi1iizmbxpw7gf3nr1g1c1-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/window.py", line 47, in __init__
    self.stack = sk.Stack(self)
  File "/nix/store/kkp78b1wxdzi1iizmbxpw7gf3nr1g1c1-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/stack.py", line 62, in __init__
    self.welcome = wl.Welcome(self)
  File "/nix/store/kkp78b1wxdzi1iizmbxpw7gf3nr1g1c1-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/welcome.py", line 49, in __init__
    self.welcome = Granite.WidgetsWelcome()
TypeError: could not get a reference to type class

with the following amended build file

Build file amended
{ lib
, stdenv
, pkgs
, python3Packages
}:

python3Packages.buildPythonApplication rec {
  version = "0.2.4";
  pname = "bottles";
  name = "${pname}-${version}";
  src = pkgs.fetchFromGitHub {
    owner = "mirkobrombin";
    repo = "Bottles";
    rev = "${version}";
    sha256 = "05mf6dxnbnnmw92ir0bskslafjj9nakmjnkqipsaijpj945v399s";
  };
  buildInputs = with pkgs; [ gtk3 python3 glib gobject-introspection ];
  nativeBuildInputs= with pkgs; [wrapGAppsHook];
  propagatedBuildInputs = with pkgs.python37Packages; [
      pygobject3
      gst-python
  ] ++ [pkgs.pantheon.granite pkgs.libgee pkgs.wine];
  doCheck = false;
  patchPhase = ''
    substituteInPlace setup.py --replace /usr/share $out/usr/share
    substituteInPlace bottles/window.py --replace /usr/share $out/usr/share
    substituteInPlace com.github.mirkobrombin.bottles --replace /usr/share/ $out/usr/share/
  '';
  installPhase = ''
    mkdir -p $out/usr
    cp -r bottles data setup.py com.github.mirkobrombin.bottles $out
    python3 $out/setup.py install --prefix "$out"
  '';
  preInstall = ''
    makeWrapperArgs+=("''${gappsWrapperArgs[@]}")
  '';
}

which seems to indicate a failure to find the Granite library at runtime which I have no idea how to pass in.

Non-python dependencies like pantheon.granite should go to buildInputs.

But what you are seeing is likely caused by the strictDeps issue I mentioned. Add strictDeps = false.
And also preInstall will not run when installPhase does not contain runHook preInstall (similarly runHook postInstall).

Applying your advice (see below) yields the same runtime output but in different places :confused: :

output of the command
** (.com.github.mirkobrombin.bottles-wrapped:20486): WARNING **: 17:20:01.921: Failed to load shared library '/build/source/build/lib/libgranite.so.5.2.3' referenced by the typelib: /build/source/build/lib/libgranite.so.5.2.3: cannot open shared object file: No such file or directory
/nix/store/dmqrq9kzrah4qk9r73si8j6mzd4yjvh4-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/welcome.py:49: Warning: cannot retrieve class for invalid (unclassed) type 'void'
  self.welcome = Granite.WidgetsWelcome()
Traceback (most recent call last):
  File "/nix/store/dmqrq9kzrah4qk9r73si8j6mzd4yjvh4-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/main.py", line 59, in do_activate
    self.win = wn.Window()
  File "/nix/store/dmqrq9kzrah4qk9r73si8j6mzd4yjvh4-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/window.py", line 47, in __init__
    self.stack = sk.Stack(self)
  File "/nix/store/dmqrq9kzrah4qk9r73si8j6mzd4yjvh4-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/stack.py", line 62, in __init__
    self.welcome = wl.Welcome(self)
  File "/nix/store/dmqrq9kzrah4qk9r73si8j6mzd4yjvh4-bottles-0.2.4/usr/share/com.github.mirkobrombin.bottles/bottles/welcome.py", line 49, in __init__
    self.welcome = Granite.WidgetsWelcome()
TypeError: could not get a reference to type class
Build file
{ lib
, stdenv
, pkgs
, python3Packages
}:

python3Packages.buildPythonApplication rec {
  version = "0.2.4";
  pname = "bottles";
  name = "${pname}-${version}";
  src = pkgs.fetchFromGitHub {
    owner = "mirkobrombin";
    repo = "Bottles";
    rev = "${version}";
    sha256 = "05mf6dxnbnnmw92ir0bskslafjj9nakmjnkqipsaijpj945v399s";
  };
  buildInputs = with pkgs; [ gtk3 python3 glib gobject-introspection pantheon.granite libgee wine];
  nativeBuildInputs= with pkgs; [wrapGAppsHook];
  propagatedBuildInputs = with pkgs.python37Packages; [
      pygobject3
      gst-python
  ];
  strictDeps = false;
  doCheck = false;
  patchPhase = ''
    substituteInPlace setup.py --replace /usr/share $out/usr/share
    substituteInPlace bottles/window.py --replace /usr/share $out/usr/share
    substituteInPlace com.github.mirkobrombin.bottles --replace /usr/share/ $out/usr/share/
  '';
  installPhase = ''
    runHook preInstall
    mkdir -p $out/usr
    cp -r bottles data setup.py com.github.mirkobrombin.bottles $out
    python3 $out/setup.py install --prefix "$out"
  '';
  preInstall = ''
    makeWrapperArgs+=("''${gappsWrapperArgs[@]}")
  '';
}

Forgot that Granite is also broken: vala generates bad gir files (eg. without absolute paths) · Issue #47226 · NixOS/nixpkgs · GitHub This not very safe hack should fix that:

makeWrapperArgs+=(--prefix LD_LIBRARY_PATH : "${pantheon.granite}/lib")

Aww, that makes me sad to look at :rofl:
Forgot about that issue, is the solution to patch vala to generate absolute paths to the dependencies the gir specifies?

Wow. I never imagined all the ramification such a small package could bring to light…

I tried to add it to the preInstall, did not do the trick

This seems to do the trick:

{ lib
, stdenv
, pkgs
, gtk3
, python3
, glib
, gobject-introspection
, libgee
, wine
, pantheon
, wrapGAppsHook
}:

python3.pkgs.buildPythonApplication rec {
  pname = "bottles";
  version = "0.2.4";

  src = pkgs.fetchFromGitHub {
    owner = "mirkobrombin";
    repo = "Bottles";
    rev = version;
    sha256 = "05mf6dxnbnnmw92ir0bskslafjj9nakmjnkqipsaijpj945v399s";
  };

  nativeBuildInputs = [
    gobject-introspection
    wrapGAppsHook
  ];

  buildInputs = [
    gtk3
    glib
    pantheon.granite
    libgee
    wine
  ];

  propagatedBuildInputs = with python3.pkgs; [
    pygobject3
    gst-python
  ];

  strictDeps = false; # broken with gobject-introspection setup hook https://github.com/NixOS/nixpkgs/issues/56943
  doCheck = false; # why?
  dontWrapGApps = true; # prevent double wrapping

  postPatch = ''
    substituteInPlace setup.py --replace /usr/share share # needs to be relative due to setuptools bug https://github.com/pypa/setuptools/issues/130 (https://github.com/NixOS/nixpkgs/issues/23438)
    substituteInPlace bottles/window.py --replace /usr/share $out/share
    substituteInPlace com.github.mirkobrombin.bottles --replace /usr/share/ $out/share/
  '';

  preFixup = ''
    makeWrapperArgs+=(--prefix LD_LIBRARY_PATH : "${pantheon.granite}/lib") # unsafe hack to circumvent https://github.com/NixOS/nixpkgs/issues/47226
    makeWrapperArgs+=(--prefix PATH : "${wine}/bin") # make wine available at build time (it would be nicer if Bottles supported overriding path to wine binaries in a single place where we could replace it)
    makeWrapperArgs+=("''${gappsWrapperArgs[@]}") # prevent double wrapping
  '';
}

Thank you very much ! It does run now but it searches for wine64 that does not exist in the $PATH.

If the program tries to find wine64 in PATH, you need to add the package that contains wine64 to the PATH (maybe it is in different package than wine, we are adding). If it has a certain path (e.g. /usr/bin/wine64 hardcoded), you will need to patch it.

2 Likes

If anyone is curious about the strictDeps part, I made an issue Split package (optionally) (#337) · Issues · GNOME / gobject-introspection · GitLab where I am trying to distill, distill, distill this these issues down to the root problem.