How to create a Python executable with nix flake

930 Views Asked by At

I have a directory with two files, main.py and flake.nix.

flake.nix:

{
  description = "virtual environment with python and streamlit";
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  inputs.flake-utils.url = "github:numtide/flake-utils";

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
        python = pkgs.python311;
        python_packages = python.withPackages(ps: with ps;[
          ipython
          matplotlib
          pandas

        ]);


        myDevTools = [
          python_packages
        ];
      in {
        devShells.default = pkgs.mkShell {
          buildInputs = myDevTools;
        };
      });
}

What should I use in flake.nix in order to create an executable that is equivalent to the following?

    python main.py

I want to create the executable with the command

    nix build

in the shell (it means with the necessary packages installed)

I have added apps in my file:

{
  description = "virtual environment with python and streamlit";
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  inputs.flake-utils.url = "github:numtide/flake-utils";

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
        python = pkgs.python311;
        f = ps: with ps;[
          ipython
          matplotlib
          pandas
        ];
        pip_python_packages = python.withPackages(f);

        myDevTools = [
          pip_python_packages
          pkgs.streamlit
        ];
        outputName = builtins.attrNames self.outputs self.outputs;
      in {
        devShells.default = pkgs.mkShell {
          buildInputs = myDevTools;
        };

        packages.default = pkgs.poetry2nix.mkPoetryApplication {
          projectDir = self;
        };
        apps.default = {
          program = "${python}/bin/python";
          args = [ "main.py" ];
          src = "./.";
          type = "app";
      };

      });
}

But nix runs only to open the python interpreter.

Furthermore, I enter this line

    nix/store/cxsw4x1189ppmsydhwsmssr0x65nygj7-python3-3.11.4/bin/python ./main.py

in my shell

because ${python} = cxsw4x1189ppmsydhwsmssr0x65nygj7-python3-3.11.4/bin/python

And it didn't work:

ModuleNotFoundError: No module named 'pandas'

I changed my file like this:

{
  description = "virtual environment with python and streamlit";
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  inputs.flake-utils.url = "github:numtide/flake-utils";

  outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system:
    let
      pkgs = nixpkgs.legacyPackages.${system};
      python = pkgs.python311;
      f = ps: with ps;[
        ipython
        matplotlib
        pandas
      ];
      pip_python_packages = python.withPackages(f);

      myDevTools = [
        pip_python_packages
        pkgs.streamlit
      ];
      outputName = builtins.attrNames self.outputs self.outputs;
    in {
      devShells.default = pkgs.mkShell {
        buildInputs = myDevTools;
      };

      packages.default = pkgs.poetry2nix.mkPoetryApplication {
        projectDir = self;
      };

      apps.default = flake-utils.lib.mkApp {
        program = "${pip_python_packages}/bin/python";
        args = [ "${self}/main.py" ];
      };
    });
}

But I have this error now after running nix run:

error: … while evaluating the attribute 'pkgs.buildPythonPackage'

     at /nix/store/s1z7nb9n6r5n0r34fabp6yybwkbr8mjk-source/pkgs/development/interpreters/python/passthrufun.nix:87:5:

       86|     withPackages = import ./with-packages.nix { inherit buildEnv pythonPackages;};
       87|     pkgs = pythonPackages;
         |     ^
       88|     interpreter = "${self}/bin/${executable}";

   … while calling the 'mapAttrs' builtin

     at /nix/store/s1z7nb9n6r5n0r34fabp6yybwkbr8mjk-source/pkgs/development/interpreters/python/passthrufun.nix:31:8:

       30|           value;
       31|     in lib.mapAttrs func items;
         |        ^
       32|   in ensurePythonModules (callPackage

   (stack trace truncated; use '--show-trace' to show the full trace)

   error: getting status of '/nix/store/c274sjvcr30c80429v9kpn4n2q0ic6n9-source/poetry.lock': No

such file or directory

1

There are 1 best solutions below

0
On

Old question, but maybe this helps.

Quite a lot of things are wrong here.

But nix runs only to open the python interpreter.

Yes - args means nothing here so is ignored. Only type and program mean anything.

And it didn't work:

ModuleNotFoundError: No module named 'pandas'

This is because python is just that - the Python runtime. Your libraries are in their own derivations, so inaccessible from that derivation.

If you're using poetry2nix then you should lean on that more. See their template flake.

As you didn't include a pyproject.toml it's hard to recreate your setup, but by adding those packages with:

poetry add ipython streamlit matplotlib

You can then try something a bit more like this (note that poetry2nix now warns against using the nixpkgs version):

{
  description = "virtual environment with python and streamlit";
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  inputs.flake-utils.url = "github:numtide/flake-utils";

  inputs = {
    poetry2nix = {
      url = "github:nix-community/poetry2nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };
  outputs = { self, nixpkgs, flake-utils, poetry2nix }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
        inherit (poetry2nix.lib.mkPoetry2Nix { inherit pkgs; }) mkPoetryApplication;

      in {
        devShells.default = pkgs.mkShell {
          inputsFrom = [ self.packages.${system}.default ];
        };

        packages.default = mkPoetryApplication {
          projectDir = self;
        };
      }
    );
}