From cba66d1b8b786ef2eb23e475c776f05e4d80d3b9 Mon Sep 17 00:00:00 2001
From: Valentin Gagarin <valentin.gagarin@tweag.io>
Date: Tue, 4 Mar 2025 11:10:43 +0100
Subject: [PATCH] allow adding extra Python packages

---
 panel/default.nix                     |  8 ++-----
 panel/nix/overlay.nix                 | 11 +++++++++
 panel/nix/package.nix                 | 34 +++++++++++++--------------
 panel/nix/python-packages/default.nix | 32 +++++++++++++++++++++++++
 4 files changed, 62 insertions(+), 23 deletions(-)
 create mode 100644 panel/nix/overlay.nix
 create mode 100644 panel/nix/python-packages/default.nix

diff --git a/panel/default.nix b/panel/default.nix
index 9931a957..b0ec435e 100644
--- a/panel/default.nix
+++ b/panel/default.nix
@@ -4,15 +4,11 @@
   pkgs ? import sources.nixpkgs {
     inherit system;
     config = { };
-    overlays = [ ];
+    overlays = [ (import ./nix/overlay.nix) ];
   },
 }:
 let
-  package =
-    let
-      callPackage = pkgs.lib.callPackageWith (pkgs // pkgs.python3.pkgs);
-    in
-    callPackage ./nix/package.nix { };
+  package = pkgs.callPackage ./nix/package.nix { };
 
   pkgs' = pkgs.extend (_final: _prev: { panel = package; });
 
diff --git a/panel/nix/overlay.nix b/panel/nix/overlay.nix
new file mode 100644
index 00000000..88c8df9c
--- /dev/null
+++ b/panel/nix/overlay.nix
@@ -0,0 +1,11 @@
+/**
+  Nixpkgs overlay adding extra packages needed for the application
+*/
+_: prev:
+let
+  extraPython3Packages = prev.callPackage ./python-packages { };
+
+in
+{
+  python3 = prev.lib.attrsets.recursiveUpdate prev.python3 { pkgs = extraPython3Packages; };
+}
diff --git a/panel/nix/package.nix b/panel/nix/package.nix
index cd6fd973..81209cd6 100644
--- a/panel/nix/package.nix
+++ b/panel/nix/package.nix
@@ -1,13 +1,7 @@
 {
   lib,
-  buildPythonPackage,
-  dj-database-url,
-  django-compressor,
-  django-debug-toolbar,
-  django-libsass,
-  django_4,
-  setuptools,
   sqlite,
+  python3,
 }:
 let
   src =
@@ -31,7 +25,7 @@ let
     include-package-data = true
   '';
 in
-buildPythonPackage {
+python3.pkgs.buildPythonPackage {
   pname = name;
   inherit (pyproject.project) version;
   pyproject = true;
@@ -42,15 +36,21 @@ buildPythonPackage {
     cp ${builtins.toFile "source" pyproject-toml} pyproject.toml
   '';
 
-  propagatedBuildInputs = [
-    dj-database-url
-    django-compressor
-    django-debug-toolbar
-    django-libsass
-    django_4
-    setuptools
-    sqlite
-  ];
+  propagatedBuildInputs =
+    let
+      pythonPackages = with python3.pkgs; [
+        dj-database-url
+        django-compressor
+        django-debug-toolbar
+        django-libsass
+        django_4
+        setuptools
+      ];
+    in
+    [
+      sqlite
+    ]
+    ++ pythonPackages;
 
   postInstall = ''
     mkdir -p $out/bin
diff --git a/panel/nix/python-packages/default.nix b/panel/nix/python-packages/default.nix
new file mode 100644
index 00000000..40d9dcb0
--- /dev/null
+++ b/panel/nix/python-packages/default.nix
@@ -0,0 +1,32 @@
+/**
+  Collection of locally provided Python packages.
+
+  Add packages by creating a directory containing a `default.nix` file.
+  The directory name will be used for the attribute name in package set.
+
+  A package crecipe can use Python packages in its argument directly, e.g.
+
+  ```nix
+  { fetchFromGitHub, buildPythonPackage, django_4 }:
+  {
+    # ...
+  }
+  ```
+*/
+{ pkgs }:
+let
+  callPackage = pkgs.lib.callPackageWith (pkgs // pkgs.python3.pkgs // extraPython3Packages);
+
+  extraPython3Packages =
+    let
+      dir = toString ./.;
+    in
+    with builtins;
+    listToAttrs (
+      map (name: {
+        inherit name;
+        value = callPackage (dir + "/${name}") { };
+      }) (attrNames (readDir dir))
+    );
+in
+extraPython3Packages