Nix flake direnv fails to build pycairo

Hi all,

Trying to build a python development using flakes and direnv. Having issues with matplotlib actually producing a plot as it seems to not default to having a GUI backend.

I have tried to use tkinter (using poetry and as an external package) but for some reason it shows this error: ModuleNotFoundError: No module named ‘_tkinter’ when running python code in the shell, which led me to try using GTK3.

I believe I am close to getting GTK3 to work as I am able to install its requirements pycairo and PyGObject. However, when I run nix develop I get the following error:


       > Found ninja-1.11.1 at /nix/store/ykfsx9m7vvp8xq3i4vgkymcx51a7ckjy-ninja-1.11.1/bin/ninja
       > meson: enabled parallel building
       > building
       > Executing pipBuildPhase
       > Creating a wheel...
       > WARNING: The directory '/homeless-shelter/.cache/pip' or its parent directory is not owned or is not writable by the current user. The cache has been disabled. Check the permissions and owner of that directory. If executing pip with sudo, you should use sudo's -H flag.
       > ERROR: Directory '.' is not installable. Neither 'setup.py' nor 'pyproject.toml' found.

I am not sure how to resolve this. In the little I can find from google it seems that I may need to override the pycairo package, but I am not sure how to go about doing this as I am still new to the Nix ecosystem. I have tried downgrading pycairo to 1.21.0 to see if this impacted it but no change.

Any advice on either error would be greatly appreciated!

This is my flake:

{
  description = "Application packaged using poetry2nix";

  inputs.flake-utils.url = "github:numtide/flake-utils";
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  inputs.poetry2nix = {
    url = "github:nix-community/poetry2nix";
    inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = { self, nixpkgs, flake-utils, poetry2nix }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        # see https://github.com/nix-community/poetry2nix/tree/master#api for more functions and examples.
        inherit (poetry2nix.legacyPackages.${system}) mkPoetryEnv;
        pkgs = import nixpkgs {inherit system;};
        python = pkgs.python310;
        pythonEnv = mkPoetryEnv {
        	inherit python;
        	projectDir = ./.;
        	preferWheels = true;
        };
      in 
      {
	#packages.default = mkPoetryEnv {
        #  projectDir = ./.;
        #  python = pkgs.python310;
        #};
        devShells.default = pkgs.mkShell {
          buildInputs = [pythonEnv];
          packages = [ 
          	poetry2nix.packages.${system}.poetry 
          	pkgs.cairo
          	pkgs.pkg-config
		pkgs.gobject-introspection
		pkgs.tk
          	];
        };
      });
}

This is my pyproject.toml

[tool.poetry]
name = "test"
version = "0.1.0"
description = ""
authors = ["djmaupin <dmaupin@bond.edu.au>"]
readme = "README.md"

[tool.poetry.dependencies]
python = ">=3.10,<3.12"
numpy = "^1.24.2"
scipy = "^1.10.1"
pandas = "^1.5.3"
matplotlib = "^3.7.1"
setuptools = "^67.6.0"
ninja = "^1.11.1"
pygobject = "^3.44.0"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

Did you have any luck resolving this? I’m getting exactly the same issue here.

1 Like

Unfortunately not. I am not sure how to trouble shoot this. I think I need to add some package overrides in the flake, but I don’t know how to go about that and what I would specifically override

I think I have this working, I’m not sure why in the standard overrides ninja is there, it doesn’t seem to be used with the latest version of pycario.

This seems to work for me


          poetryEnv = pkgs.poetry2nix.mkPoetryEnv {
            projectDir = ./.;
            python = pkgs.python310;
            overrides = pkgs.poetry2nix.overrides.withDefaults (self: super: {
              pycairo = super.pycairo.overridePythonAttrs (
                old: {
                  nativeBuildInputs = [
                    self.meson
                    pkgs.buildPackages.pkg-config
                  ];
                }
              );
              pygobject = super.pygobject.overridePythonAttrs (
                old: {
                  buildInputs = (old.buildInputs or [ ]) ++ [ super.setuptools ];
                }
              );
            });
          };

At least my python code appears to be running :slight_smile:

1 Like

I think this helped me get closer! I had to add pkgs.buildPackages.ninja to the native build inputs (not sure why, maybe pycairo still needed it in my environment?)

Python code isn’t running - I have matplotlib.use(‘GTK3Agg’) but I get errors now that the GTK namespace is not available. It seems one of the fixes to this error is to add the gobject-introspection package, which I have but still not working.

Did you come across this while getting it to work?

This got me far enough that in my devshell works. Full flake as it seems like we’re doing something similar.

{
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

  inputs.poetry2nix = {
    url = "github:nix-community/poetry2nix";
    inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = { self, nixpkgs, poetry2nix }:
    let
      systems = [ "x86_64-linux" ];
      forAllSystems = nixpkgs.lib.genAttrs systems;
    in
    {
      devShells = forAllSystems (system:
        let
          pkgs = import nixpkgs {
            inherit system;
            overlays = [ poetry2nix.overlay ];
          };

          poetryEnv = pkgs.poetry2nix.mkPoetryEnv {
            projectDir = ./.;
            python = pkgs.python310;
            overrides = pkgs.poetry2nix.overrides.withDefaults (self: super: {
              pycairo = super.pycairo.overridePythonAttrs (
                old: {
                  nativeBuildInputs = [
                    self.meson
                    pkgs.buildPackages.pkg-config
                  ];
                }
              );
              pygobject = super.pygobject.overridePythonAttrs (
                old: {
                  buildInputs = (old.buildInputs or [ ]) ++ [ super.setuptools ];
                }
              );
            });
          };
        in
        {
          devShell."${system}" = pkgs.mkShell {
            buildInputs = with pkgs; [
              poetry
              cairo
              pkg-config
              python310Packages.gst-python
              gobject-introspection
              poetryEnv
            ];
          };
        });

    };
}

Note with that shell I can run my application via python3 app.py and poetry run python3 app.py, I don’t like having that gst-python as the build input for devshell. Sure there’s a better way of doing that…