mach-nix icon indicating copy to clipboard operation
mach-nix copied to clipboard

How to use a wheel from local file?

Open bjornfor opened this issue 4 years ago • 4 comments

Hi, I wonder how I can pass a local .whl file to mach-nix, to be included in the final python environment. (The wheel file I need is not hosted on pypi. I plan to use nixpkgs' requireFile to get it.)

I tried passing it in packagesExtra, but that doesn't work:

[...]
unpacking source archive /nix/store/w8a0dh4gkq17xc46m778xxrszc33s8k4-tensorboard-1.15.0-py3-none-any.whl
do not know how to unpack source archive /nix/store/w8a0dh4gkq17xc46m778xxrszc33s8k4-tensorboard-1.15.0-py3-none-any.whl
builder for '/nix/store/g98f6z283kjpkb1hj8i8p811ivzgs4zq-package-requirements.drv' failed with exit code 1

(The above file is just for testing.)

bjornfor avatar Nov 28 '20 18:11 bjornfor

Simplified wheel support is indeed a missing feature in mach-nix But you can still use buildPythonPackage from mach-nix and manually set format = "wheel".

example:

mach-nix.mkPython {
    packagesExtra = [
      (mach-nix.buildPythonPackage {
        pname = "requests";
        version = "2.25.0";
        format = "wheel";
        src = /tmp/requests-2.25.0-py2.py3-none-any.whl;
        requirements = ''
          chardet
          idna
          urllib3
          certifi
        '';
      })
    ];
}

Just make sure to set pname, version and requirements accordingly, otherwise it will fail since it doesn't yet support automatic metadata extraction from wheels.

DavHau avatar Nov 29 '20 05:11 DavHau

That works, thanks!

FYI, I'm testing import-from-derivation to get the requirements.txt contents from the wheel itself, by collecting Requires-Dist: lines from ${unpacked_wheel_file}/${wheel_name}.dist-info/METADATA" with Nix' builtins.match. Seems to work. Nix snippet below.

  requirements =
    let
      text = builtins.readFile "${unpacked_wheel_file}/${wheel_name}.dist-info/METADATA";
      lines = builtins.filter (x: x != [] && x != "") (builtins.split "\n" text);
      # toRequirement :: String -> String (or null)
      toRequirement = line:
        let
          m =
            builtins.match "Requires-Dist: (.*)" line;
        in
          if m == null
          then null
          else
            # Return the match group, unless it contains "; extra ==" (ref.
            # https://github.com/DavHau/mach-nix/pull/419).
            let
              req = builtins.elemAt m 0;  # the first match group
            in
              if builtins.match ".*; extra == .*" req == []
              then null
              else req;
      requirementsLines = (lib.filter (x: x != null) (map toRequirement lines));
      requirementsText = lib.concatStringsSep "\n" requirementsLines;
    in
      #builtins.trace "Extracted requirements.txt from METADATA:\n${requirementsText}"
      requirementsText;

UPDATED(2022-04-07): Filter out Provides-Extra lines, ref. https://github.com/DavHau/mach-nix/pull/419.

bjornfor avatar Nov 29 '20 12:11 bjornfor

Nice, something like this should also go into mach-nix.

But since we're already doing IFD, we could also just use wheel2json from the wheel-inspect package, then parse the json with nix.

DavHau avatar Nov 30 '20 05:11 DavHau

Cross-reference: https://github.com/DavHau/mach-nix/issues/276.

bjornfor avatar Mar 23 '22 18:03 bjornfor