Packaging a single python script with runtime dependencies

I’m trying to package a python script (whatmp3) that has runtime dependencies as an overlay to have it part of pkgs in my config, so a service can call ${pkgs.whatmp3} and do stuff.

The problem I’m currently facing is that even though I’ve wrapped the script with wrapProgram, I get a .wrapped file in nix store along with the script but it still fails due to “command not found” on the runtime dependencies.

It doesn’t need to be as an overlay but I just went with it cause I thought it’d be easier.

Here’s what I have so far:

{ inputs, ... }@args: self: super: rec {

  whatmp3 = super.python3Packages.buildPythonApplication rec {
    pname = "whatmp3";
    version = "v3.8";

    src = super.fetchFromGitHub rec {
      inherit pname version;
      name = pname;
      rev = version;
      owner = "creaaidev";
      repo = "whatmp3";
      sha256 = "sha256-9ayqXqSD4DEvLTvtZ2zJTwW/YdkMZwnZ7tACAqJXTHM=";
    };

    installPhase = ''install -Dm755 whatmp3.py $out/bin/whatmp3'';
    postInstall = ''
      wrapProgram $out/bin/whatmp3 \
        --set PATH ${args.lib.makeBinPath [
          # Hard requirements
          super.flac
          super.lame
          # Optional deps depending on encoding types
          super.opusTools
          super.vorbis-tools
          super.ffmpeg
          super.vorbisgain
          super.mp3gain
        ]}
    '';
  };
}

Here’s the two generated files in nix store:
whatmp3

#! /nix/store/8fv91097mbh5049i9rglc73dx6kjg3qk-bash-5.2-p15/bin/bash -e
PATH=${PATH:+':'$PATH':'}
PATH=${PATH/':''/nix/store/dc9dym5sz21halld5yyzyfcfs3knf8qg-whatmp3-v3.8/bin'':'/':'}
PATH='/nix/store/dc9dym5sz21halld5yyzyfcfs3knf8qg-whatmp3-v3.8/bin'$PATH
PATH=${PATH#':'}
PATH=${PATH%':'}
export PATH
PATH=${PATH:+':'$PATH':'}
PATH=${PATH/':''/nix/store/763kk6xg6vaslzh1hgvwgdk1h582b7s3-python3-3.10.12/bin'':'/':'}
PATH='/nix/store/763kk6xg6vaslzh1hgvwgdk1h582b7s3-python3-3.10.12/bin'$PATH
PATH=${PATH#':'}
PATH=${PATH%':'}
export PATH
export PYTHONNOUSERSITE='true'
exec -a "$0" "/nix/store/dc9dym5sz21halld5yyzyfcfs3knf8qg-whatmp3-v3.8/bin/.whatmp3-wrapped"  "$@"

.whatmp3-wrapped

#!/nix/store/763kk6xg6vaslzh1hgvwgdk1h582b7s3-python3-3.10.12/bin/python3

import sys;import site;import functools;sys.argv[0] = '/nix/store/dc9dym5sz21halld5yyzyfcfs3knf8qg-whatmp3-v3.8/bin/whatmp3';functools.reduce(lambda k, p: site.addsitedir(p, k), [], site._init_pathinfo());
import argparse
import multiprocessing
import os
import re
import shutil
import sys
import threading
from fnmatch import fnmatch

VERSION = "3.8"

(rest of the file is identical to original)

Any idea what the problem might be? Here’s the script.
Thanks.

buildPythonApplication / buildPythonPackage take a few arguments (like makeWrapperArgs ) for controlling how they wrap generated executables (which they already do by default during the fixup phase). https://nixos.org/manual/nixpkgs/stable/#buildpythonpackage-parameters

I suspect they are clobbering your wrappers.

You probably want something like:

1 Like

Thanks a lot, that did fix it!

{ inputs, ... }@args: self: super: rec {

  whatmp3 = super.python3Packages.buildPythonApplication rec {
    pname = "whatmp3";
    version = "v3.8";

    # whatmp3 seems abandoned anyway so I'm using my own fork for the setup.py
    src = super.fetchFromGitHub rec {
      inherit pname version;
      name = pname;
      rev = version;
      owner = "creaaidev";
      repo = "whatmp3";
      sha256 = "sha256-9ayqXqSD4DEvLTvtZ2zJTwW/YdkMZwnZ7tACAqJXTHM=";
    };

    installPhase = ''install -Dm755 whatmp3.py $out/bin/whatmp3'';
    preFixup = ''
      makeWrapperArgs+=(--prefix PATH : ${args.lib.makeBinPath [
        # Hard requirements
        super.flac
        super.lame # lmao
        # Optional deps depending on encoding types
        super.opusTools
        super.vorbis-tools
        super.ffmpeg
        super.vorbisgain
        super.mp3gain
      ]})
    '';
  };
}
1 Like

A note for anyone else landing on this discussion: the proper way to do this is to pass runtime dependencies through the dependencies attribute, as documented in the link to buildPythonPackage parameters above. These will be passed as arguments to the makeWrapper utility automatically.

installPhase = ''install -Dm755 whatmp3.py $out/bin/whatmp3'';
dependencies = [ pkgs.flac pkgs.ffmpeg ]; # you get the idea
1 Like