Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jupyter.lib: init #278315

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/packages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ firefox.section.md
fish.section.md
fuse.section.md
ibus.section.md
jupyter.section.md
kakoune.section.md
linux.section.md
locales.section.md
Expand Down
32 changes: 32 additions & 0 deletions doc/packages/jupyter.section.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# jupyter {#sec-jupyter}

Jupyter has different frontends that can be configured: jupyter-console and
jupyter-notebook. The approach is the same:
1. create a folder that contains all the jupyter kernels
2. wrap the executables

```nix
let
definitions = {
python = jupyterLib.mkKernelFromPythonEnv (python3.withPackages(ps: [
ps.numpy ]);
haskell = jupyterLib.mkKernelFromHaskellEnv (pkgs.haskellPackages.ghcWithPackages(hs: [ hs.aeson
]);
# ... and all other kernels you are interested in
};
myKernels = jupyter-kernel.create {
inherit definitions;
};
in
# pseudocode, real code in next sections
jupyter frontend wrapped with JUPYTER_PATH=myKernels
```


## How to run jupyter-console with arbitrary kernels ? {#sec-jupyter-console}

```nix
myJupyterConsole = jupyter-console.mkConsole {
inherit definitions;
}
```
26 changes: 3 additions & 23 deletions pkgs/applications/editors/jupyter/console.nix
Original file line number Diff line number Diff line change
@@ -1,36 +1,16 @@
{ python3
, jupyter-kernel
, jupyterLib
, lib
}:

let
mkConsole = {
definitions ? jupyter-kernel.default
, kernel ? null
}:
(python3.buildEnv.override {
extraLibs = [ python3.pkgs.jupyter-console ];
makeWrapperArgs = [
"--set JUPYTER_PATH ${jupyter-kernel.create { inherit definitions; }}"
] ++ lib.optionals (kernel != null) [
"--add-flags --kernel"
"--add-flags ${kernel}"
];
}).overrideAttrs (oldAttrs: {
# To facilitate running nix run .#jupyter-console
meta = oldAttrs.meta // { mainProgram = "jupyter-console"; };
});

in

{
# Build a console derivation with an arbitrary set of definitions, and an optional kernel to use.
# If the kernel argument is not supplied, Jupyter console will pick a kernel to run from the ones
# available on the system.
inherit mkConsole;
inherit (jupyterLib) mkConsole;

# An ergonomic way to start a console with a single kernel.
withSingleKernel = definition: mkConsole {
withSingleKernel = definition: jupyterLib.mkConsole {
definitions = lib.listToAttrs [(lib.nameValuePair definition.language definition)];
kernel = definition.language;
};
Expand Down
3 changes: 3 additions & 0 deletions pkgs/applications/editors/jupyter/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
{ python3
, jupyter-kernel
, definitions ? jupyter-kernel.default
, callPackage
}:

let
Expand All @@ -12,6 +13,8 @@ let
makeWrapperArgs = ["--set JUPYTER_PATH ${jupyterPath}"];
}).overrideAttrs(oldAttrs: {
meta = oldAttrs.meta // { mainProgram = "jupyter-notebook"; };

passthru.tests = callPackage ./tests {};
});
in

Expand Down
18 changes: 2 additions & 16 deletions pkgs/applications/editors/jupyter/kernel.nix
Original file line number Diff line number Diff line change
@@ -1,23 +1,9 @@
{ lib, stdenv, python3}:
{ lib, stdenv, python3, jupyterLib }:

let

default = {
python3 = let
env = (python3.withPackages (ps: with ps; [ ipykernel ]));
in {
displayName = "Python 3";
argv = [
env.interpreter
"-m"
"ipykernel_launcher"
"-f"
"{connection_file}"
];
language = "python";
logo32 = "${env}/${env.sitePackages}/ipykernel/resources/logo-32x32.png";
logo64 = "${env}/${env.sitePackages}/ipykernel/resources/logo-64x64.png";
};
python3 = jupyterLib.mkKernelFromPythonEnv (python3.withPackages (ps: []));
};

in
Expand Down
81 changes: 81 additions & 0 deletions pkgs/applications/editors/jupyter/lib.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{ jupyter-kernel, python3, lib, ...}:
{
/* Generates a kernel definition from a haskell environment

Example:
let ghcEnv = pkgs.haskellPackages.ghcWithPackages (p: [ p.aeson ]);
in mkKernelFromHaskellEnv ghcEnv;

Type:
mkKernelFromHaskellEnv :: Derivation -> AttrSet
*/
mkKernelFromHaskellEnv = ghcEnv:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect to have 1 file per kernel. And perhaps not constructing raw Jupyter kernelspecs like this, because then we have to worry about making sure they're all valid. IIRC there is currently some machinery in Nixpkgs for constructing these with some type safety.

Copy link
Member Author

@teto teto Jan 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect to have 1 file per kernel

ok

And perhaps not constructing raw Jupyter kernelspecs like this, because then we have to worry about making sure they're all valid. IIRC there is currently some machinery in Nixpkgs for constructing these with some type safety.

there is in nixos/modules/services/development/jupyter/./kernel-options.nix. It's possible to use those outside of the module but it's not trivial IMO. It can be added transparently later.

let
ghcEnv' = ghcEnv.withPackages (p: [ p.ihaskell ]);
in

{
displayName = "Haskell";
argv = [
"${ghcEnv'}/bin/ihaskell"
"-l"
# the ihaskell flake does `-l $(${env}/bin/ghc --print-libdir`
# we guess the path via hardcoded
# we can't use name else we get the 'with-packages' suffix
"${ghcEnv}/lib/ghc-${ghcEnv.version}"
"kernel"
"{connection_file}"
];
language = "haskell";
logo32 = null;
logo64 = null;
};


/* Generates a kernel definition from a python environment
Example:
let pyEnv = pkgs.python3.withPackages (p: [ p.numpy ]);
in mkKernelFromPythonEnv pyEnv;

Type:
mkKernelFromPythonEnv :: Derivation -> AttrSet
*/
mkKernelFromPythonEnv = env: let
env' = env.override(prev: {
# fastai
extraLibs = prev.extraLibs ++ [ env.python.pkgs.ipykernel ];
});

in
{
displayName = "Python 3";
argv = [
env'.interpreter
"-m"
"ipykernel_launcher"
"-f"
"{connection_file}"
];
language = "python";
logo32 = "${env}/${env.sitePackages}/ipykernel/resources/logo-32x32.png";
logo64 = "${env}/${env.sitePackages}/ipykernel/resources/logo-64x64.png";
};

mkConsole = {
definitions ? jupyter-kernel.default
, kernel ? null
}:
(python3.buildEnv.override {
extraLibs = [ python3.pkgs.jupyter-console ];
makeWrapperArgs = [
"--set JUPYTER_PATH ${jupyter-kernel.create { inherit definitions; }}"
] ++ lib.optionals (kernel != null) [
"--add-flags --kernel"
"--add-flags ${kernel}"
];
}).overrideAttrs (oldAttrs: {
# To facilitate running nix run .#jupyter-console
meta = oldAttrs.meta // { mainProgram = "jupyter-console"; };
});

}
11 changes: 11 additions & 0 deletions pkgs/applications/editors/jupyter/tests/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{ pkgs }:
{
jupyter-all = pkgs.jupyter.override {
definitions = {
clojure = pkgs.clojupyter.definition;
octave = pkgs.octave-kernel.definition;
# wolfram = wolfram-for-jupyter-kernel.definition; # unfree
};
};

}
1 change: 1 addition & 0 deletions pkgs/top-level/aliases.nix
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ mapAliases ({
jfbview = throw "'jfbview' has been removed, because it depends on an outdated and insecure version of mupdf"; # Added 2023-06-27
jira-cli = throw "jira-cli was removed because it is no longer maintained"; # Added 2023-02-28
join-desktop = throw "'join-desktop' has been removed because it is unmaintained upstream"; # Added 2023-10-04
jupyter-all = jupyter.tests;

# Julia

Expand Down
9 changes: 1 addition & 8 deletions pkgs/top-level/all-packages.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9721,14 +9721,7 @@ with pkgs;
jupp = callPackage ../applications/editors/jupp { };

jupyter = callPackage ../applications/editors/jupyter { };

jupyter-all = jupyter.override {
definitions = {
clojure = clojupyter.definition;
octave = octave-kernel.definition;
# wolfram = wolfram-for-jupyter-kernel.definition; # unfree
};
};
jupyterLib = callPackage ../applications/editors/jupyter/lib.nix { };

jupyter-console = callPackage ../applications/editors/jupyter/console.nix { };

Expand Down