about summary refs log tree commit diff
path: root/nixpkgs/pkgs/development/tools/poetry2nix/poetry2nix/default.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/pkgs/development/tools/poetry2nix/poetry2nix/default.nix')
-rw-r--r--nixpkgs/pkgs/development/tools/poetry2nix/poetry2nix/default.nix252
1 files changed, 252 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/development/tools/poetry2nix/poetry2nix/default.nix b/nixpkgs/pkgs/development/tools/poetry2nix/poetry2nix/default.nix
new file mode 100644
index 000000000000..967f0d666cb4
--- /dev/null
+++ b/nixpkgs/pkgs/development/tools/poetry2nix/poetry2nix/default.nix
@@ -0,0 +1,252 @@
+{ pkgs ? import <nixpkgs> {}
+, lib ? pkgs.lib
+, poetry ? null
+, poetryLib ? import ./lib.nix { inherit lib pkgs; }
+}:
+
+let
+  inherit (poetryLib) isCompatible readTOML;
+
+  # Poetry2nix version
+  version = "1.1.0";
+
+  /* The default list of poetry2nix override overlays */
+  defaultPoetryOverrides = (import ./overrides.nix { inherit pkgs lib; });
+
+  mkEvalPep508 = import ./pep508.nix {
+    inherit lib;
+    stdenv = pkgs.stdenv;
+  };
+
+  getFunctorFn = fn: if builtins.typeOf fn == "set" then fn.__functor else fn;
+
+  getAttrDefault = attribute: set: default: (
+    if builtins.hasAttr attribute set
+    then builtins.getAttr attribute set
+    else default
+  );
+
+  # Map SPDX identifiers to license names
+  spdxLicenses = lib.listToAttrs (lib.filter (pair: pair.name != null) (builtins.map (v: { name = if lib.hasAttr "spdxId" v then v.spdxId else null; value = v; }) (lib.attrValues lib.licenses)));
+  # Get license by id falling back to input string
+  getLicenseBySpdxId = spdxId: getAttrDefault spdxId spdxLicenses spdxId;
+
+  #
+  # Returns an attrset { python, poetryPackages } for the given lockfile
+  #
+  mkPoetryPython =
+    { poetrylock
+    , poetryPkg
+    , overrides ? [ defaultPoetryOverrides ]
+    , meta ? {}
+    , python ? pkgs.python3
+    , pwd ? null
+    }@attrs: let
+      lockData = readTOML poetrylock;
+      lockFiles = lib.getAttrFromPath [ "metadata" "files" ] lockData;
+
+      specialAttrs = [ "poetrylock" "overrides" ];
+      passedAttrs = builtins.removeAttrs attrs specialAttrs;
+
+      evalPep508 = mkEvalPep508 python;
+
+      # Filter packages by their PEP508 markers
+      partitions = let
+        supportsPythonVersion = pkgMeta: if pkgMeta ? marker then (evalPep508 pkgMeta.marker) else true;
+      in
+        lib.partition supportsPythonVersion lockData.package;
+
+      compatible = partitions.right;
+      incompatible = partitions.wrong;
+
+      # Create an overriden version of pythonPackages
+      #
+      # We need to avoid mixing multiple versions of pythonPackages in the same
+      # closure as python can only ever have one version of a dependency
+      baseOverlay = self: super:
+        let
+          getDep = depName: if builtins.hasAttr depName self then self."${depName}" else throw "foo";
+
+          lockPkgs = builtins.listToAttrs (
+            builtins.map (
+              pkgMeta: rec {
+                name = pkgMeta.name;
+                value = self.mkPoetryDep (
+                  pkgMeta // {
+                    inherit pwd;
+                    source = getAttrDefault "source" pkgMeta null;
+                    files = lockFiles.${name};
+                    pythonPackages = self;
+                  }
+                );
+              }
+            ) compatible
+          );
+        in
+          lockPkgs;
+
+      overlays = builtins.map getFunctorFn (
+        [
+          (
+            self: super: {
+              mkPoetryDep = self.callPackage ./mk-poetry-dep.nix {
+                inherit pkgs lib python poetryLib;
+              };
+              poetry = poetryPkg;
+            }
+          )
+          # Null out any filtered packages, we don't want python.pkgs from nixpkgs
+          (self: super: builtins.listToAttrs (builtins.map (x: { name = x.name; value = null; }) incompatible))
+          # Create poetry2nix layer
+          baseOverlay
+        ] ++ # User provided overrides
+        overrides
+      );
+
+      packageOverrides = lib.foldr lib.composeExtensions (self: super: {}) overlays;
+
+      py = python.override { inherit packageOverrides; self = py; };
+    in
+      {
+        python = py;
+        poetryPackages = map (pkg: py.pkgs.${pkg.name}) compatible;
+      };
+
+  /* Returns a package with a python interpreter and all packages specified in the poetry.lock lock file.
+
+     Example:
+       poetry2nix.mkPoetryEnv { poetrylock = ./poetry.lock; python = python3; }
+  */
+  mkPoetryEnv =
+    { poetrylock
+    , overrides ? [ defaultPoetryOverrides ]
+    , meta ? {}
+    , pwd ? null
+    , python ? pkgs.python3
+    }:
+      let
+        poetryPkg = poetry.override { inherit python; };
+        py = mkPoetryPython (
+          {
+            inherit poetryPkg poetrylock overrides meta python pwd;
+          }
+        );
+      in
+        py.python.withPackages (_: py.poetryPackages);
+
+  /* Creates a Python application from pyproject.toml and poetry.lock */
+  mkPoetryApplication =
+    { src
+    , pyproject
+    , poetrylock
+    , overrides ? [ defaultPoetryOverrides ]
+    , meta ? {}
+    , python ? pkgs.python3
+    , pwd ? null
+    , ...
+    }@attrs: let
+      poetryPkg = poetry.override { inherit python; };
+
+      py = (
+        mkPoetryPython {
+          inherit poetryPkg poetrylock overrides meta python pwd;
+        }
+      ).python;
+
+      pyProject = readTOML pyproject;
+
+      specialAttrs = [ "pyproject" "poetrylock" "overrides" ];
+      passedAttrs = builtins.removeAttrs attrs specialAttrs;
+
+      getDeps = depAttr: let
+        deps = getAttrDefault depAttr pyProject.tool.poetry {};
+        depAttrs = builtins.map (d: lib.toLower d) (builtins.attrNames deps);
+      in
+        builtins.map (dep: py.pkgs."${dep}") depAttrs;
+
+      getInputs = attr: getAttrDefault attr attrs [];
+      mkInput = attr: extraInputs: getInputs attr ++ extraInputs;
+
+      buildSystemPkgs = poetryLib.getBuildSystemPkgs {
+        inherit pyProject;
+        pythonPackages = py.pkgs;
+      };
+
+    in
+      py.pkgs.buildPythonApplication (
+        passedAttrs // {
+          pname = pyProject.tool.poetry.name;
+          version = pyProject.tool.poetry.version;
+
+          format = "pyproject";
+
+          nativeBuildInputs = [ pkgs.yj ];
+          buildInputs = mkInput "buildInputs" buildSystemPkgs;
+          propagatedBuildInputs = mkInput "propagatedBuildInputs" (getDeps "dependencies") ++ ([ py.pkgs.setuptools ]);
+          checkInputs = mkInput "checkInputs" (getDeps "dev-dependencies");
+
+          passthru = {
+            python = py;
+          };
+
+          postPatch = (getAttrDefault "postPatch" passedAttrs "") + ''
+            # Tell poetry not to resolve the path dependencies. Any version is
+            # fine !
+            yj -tj < pyproject.toml | python ${./pyproject-without-path.py} > pyproject.json
+            yj -jt < pyproject.json > pyproject.toml
+            rm pyproject.json
+          '';
+
+          meta = meta // {
+            inherit (pyProject.tool.poetry) description homepage;
+            license = getLicenseBySpdxId (getAttrDefault "license" pyProject.tool.poetry "unknown");
+          };
+
+        }
+      );
+
+  /* Poetry2nix CLI used to supplement SHA-256 hashes for git dependencies  */
+  cli = import ./cli.nix { inherit pkgs lib version; };
+
+  /* Poetry2nix documentation  */
+  doc = pkgs.stdenv.mkDerivation {
+    pname = "poetry2nix-docs";
+    inherit version;
+
+    src = pkgs.runCommandNoCC "poetry2nix-docs-src" {} ''
+      mkdir -p $out
+      cp ${./default.nix} $out/default.nix
+    '';
+
+    buildInputs = [
+      pkgs.nixdoc
+    ];
+
+    buildPhase = ''
+      nixdoc --category poetry2nix --description "Poetry2nix functions" --file ./default.nix > poetry2nix.xml
+    '';
+
+    installPhase = ''
+      mkdir -p $out
+      cp poetry2nix.xml $out/
+    '';
+
+  };
+
+in
+{
+  inherit mkPoetryEnv mkPoetryApplication cli doc;
+
+  /*
+  The default list of poetry2nix override overlays
+
+  Can be overriden by calling defaultPoetryOverrides.overrideOverlay which takes an overlay function
+  */
+  defaultPoetryOverrides = {
+    __functor = defaultPoetryOverrides;
+    overrideOverlay = fn: self: super: let
+      defaultSet = defaultPoetryOverrides self super;
+      customSet = fn self super;
+    in defaultSet // customSet;
+  };
+}