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

nixos/jupyter: init service #33673

Closed
wants to merge 3 commits into from
Closed

nixos/jupyter: init service #33673

wants to merge 3 commits into from

Conversation

aborsu
Copy link
Contributor

@aborsu aborsu commented Jan 9, 2018

Motivation for this change

I believe that having a configurable service for jupyter with a template to write new kernels is a wanted feature.
cfr
https://www.reddit.com/r/NixOS/comments/7oujo4/getting_all_the_jupyter_kernels/
#10713

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option build-use-sandbox in nix.conf on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nox --run "nox-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Fits CONTRIBUTING.md.

This pull requests brings a jupyter service to nixos.
It contains a default bare python3 kernel and a literal example on how to define multiple kernels.

@aborsu
Copy link
Contributor Author

aborsu commented Jan 9, 2018

@FRidh @ixxie Any feedback?

@FRidh
Copy link
Member

FRidh commented Jan 10, 2018

Related issue: #10713

example = "users";
};

password = mkOption {
Copy link
Member

Choose a reason for hiding this comment

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

I think it is better to keep this out of the store. Maybe you can point to a path and read that during runtime?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I made a compromise on that, that I think should be agreeable to all.

type = types.package;
default = (pkgs.python36.withPackages (
pythonPackages: with pythonPackages; [
notebook
Copy link
Member

Choose a reason for hiding this comment

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

ipykernel should be sufficient as the notebook should already be offered by this service

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, good catch

"python3" = {
name = "Python 3 for Machine Learning";
env = (pkgs.python36.withPackages (pythonPackages: with pythonPackages; [
notebook
Copy link
Member

Choose a reason for hiding this comment

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

same here

@FRidh FRidh mentioned this pull request Jan 10, 2018
@FRidh
Copy link
Member

FRidh commented Jan 11, 2018

I think the logic of creating a jupyter notebook with a set of kernels can be factored out of the module and into a function in Nixpkgs.

@aborsu
Copy link
Contributor Author

aborsu commented Jan 11, 2018

@FRidh I agree, but it was a bit more work.
I think it's pretty good for now.
We could provide a few additional kernels but I think this should be done in other PR.

@aborsu
Copy link
Contributor Author

aborsu commented Jan 18, 2018

@FRidh @globin
I've made a seperate package with the kernel logic, any feedback?
Let me know if you want me to change anything.
I've tested it on my server but so far only with Python kernels.
It would be great to have a Julia and R kernel so we could have the Ju Pyt R but i'm not very good in those two languages.

Copy link
Member

@FRidh FRidh left a comment

Choose a reason for hiding this comment

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

I think it is good to have a separate derivation for the kernel config, and having a new top level item for Jupyter. However, instead of making it a derivation that needs to be overriden, I suggest making jupyter a function:

kernelDefinitions: { the, other, args }: derivation

, lib
, pkgs
, python3
, python3Packages
Copy link
Member

Choose a reason for hiding this comment

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

python3 or python3Packages

@@ -0,0 +1,21 @@
{ stdenv
, lib
, pkgs
Copy link
Member

Choose a reason for hiding this comment

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

no pkgs

python3Packages.buildPythonApplication rec {
inherit (python3Packages.notebook) pname version name src LC_ALL buildInputs propagatedBuildInputs checkPhase doCheck meta;

makeWrapperArgs = ["--set JUPYTER_PATH ${jupyterPath}"];
Copy link
Member

Choose a reason for hiding this comment

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

let
 ...
in with python3.pkgs; toPythonModule (notebook.override {
  makeWrapperArgs = ["--set JUPYTER_PATH ${jupyterPath}"];
});

toPythonModule (buildPythonPackage {...}) is basically the same as buildPythonApplication. In this case I would go for the former, because the current approach requires keeping up with required attributes.

@@ -0,0 +1,66 @@
{pkgs, python3, lib, kernelDefinitions ? null }:
Copy link
Member

Choose a reason for hiding this comment

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

No pkgs

@@ -0,0 +1,66 @@
{pkgs, python3, lib, kernelDefinitions ? null }:

Copy link
Member

@FRidh FRidh Jan 20, 2018

Choose a reason for hiding this comment

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

let
  defaultKernelDefinitions = {
    ...
  };
in {python3, lib, kernelDefinitions ? defaultKernelDefinitions }:

let
kernels = if kernelDefinitions != null
then kernelDefinitions
else {
Copy link
Member

Choose a reason for hiding this comment

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

this is then defaultKernelDefinitions

"{connection_file}"
];
language = "python";
logo32 = "${env}/lib/python3.6/site-packages/ipykernel/resources/logo-32x32.png";
Copy link
Member

Choose a reason for hiding this comment

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

env.sitePackages

@aborsu
Copy link
Contributor Author

aborsu commented Jan 21, 2018

@FRidh
I didn't change everything exactly like you asked.

I'm not convinced making the top package jupyter a function is such a great idea.
The error message that I got when running nix-env -i jupyter or trying to add jupyter in my environment.systemPackages without giving it a kernelDefinition where unhelpful and I think will lead to a lot of head scratching by first time users.

error: The option value `environment.systemPackages.[definition 1-entry 1]' in `...configuration.nix' is not of type `package'.

Even if I give a default argument, the function still needs to be called.

It seems to me that override is a standard way of providing customizability to packages and will avoid a lot of pain while imo not reducing understandability or ease of use.

As always I'm ready to discuss this further. And thank you for your helpfull corrections.

@aborsu
Copy link
Contributor Author

aborsu commented Jan 31, 2018

@FRidh ping?

@@ -0,0 +1,16 @@
{ pkgs
Copy link
Member

Choose a reason for hiding this comment

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

pkgs is not used, adding jupyterKernels is better


in

kernelDefinitions: (
Copy link
Member

Choose a reason for hiding this comment

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

{ kernelDefinitions ? defaultKernelDefinitions
}: 

in {
displayName = "Python 3";
argv = [
"${env}/bin/python"
Copy link
Member

Choose a reason for hiding this comment

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

${env.interpreter}

@@ -0,0 +1,88 @@
{pkgs, lib}:
Copy link
Member

Choose a reason for hiding this comment

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

I don't think pkgs is used

in
{
defaultKernelDefinition = defaultKernelDefinition;
create = { kernelDefinitions ? defaultKernelDefinition }:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@FRidh I'm not certain this is better.
Now I'm exporting a set instead of exporting a function so I can re-use the default value in all the packages that might use it.

@@ -0,0 +1,16 @@
{ python3
, jupyterKernels
, kernelDefinitions ? jupyterKernels.defaultKernelDefinition
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is neat.



kernels = (pkgs.jupyterKernels.create {
kernelDefinitions = if cfg.kernels != null
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've basically had to move the null check here now.
I though of passing the pkgs.jupyterKernels.defaultKernelConfig as the default value for jupyter.kernels, but the it complains that it contains a reference to a derivation. (I can understand that having to build a derivation to create the doc is not the greatest).

@aborsu
Copy link
Contributor Author

aborsu commented Feb 3, 2018

@FRidh opinion?

Copy link
Contributor

@schneefux schneefux left a comment

Choose a reason for hiding this comment

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

compiles and runs basic examples

@dustinlacewell-wk
Copy link

Mind providing an example of how to get Jupyter installed with these changes?

@schneefux
Copy link
Contributor

Here is my configuration (the password is "test", change it):

  services.jupyter = {
    enable = true;
    port = 8123;
    notebookDir = "/var/www/jupyter";
    password = "'sha1:1b961dc713fb:88483270a63e57d18d43cf337e629539de1436ba'";
  };

env = (pkgs.python3.withPackages (pythonPackages: with pythonPackages; [
ipykernel
pandas
scikitlearn
Copy link
Contributor

Choose a reason for hiding this comment

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

Are these Jupyter dependencies or just nice to have packages?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ipykernel is needed, the others are just basic packages used for data science.
I was thinking of getting something inline with the jupyter dockerimages.
Base python, base data-science, data-science + spark

Copy link
Member

Choose a reason for hiding this comment

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

Keep the default as minimal as possible.

@ixxie
Copy link
Contributor

ixxie commented Apr 19, 2018 via email

@zimbatm zimbatm removed their request for review April 19, 2018 15:47
@aborsu
Copy link
Contributor Author

aborsu commented Apr 19, 2018

@ixxie for python, using the packages used by the jupyter docker images would be a good start https://github.com/jupyter/docker-stacks/tree/master/datascience-notebook

@ixxie
Copy link
Contributor

ixxie commented Apr 25, 2018

@aborsu thanks for the tip

Sorry everybody about that offtopic-ish post; I didn't realize I could reply to an email in my mail client and it would post to GitHub!

@phile314-fh
Copy link
Contributor

I have been using this for the last few weeks and it works nicely 👍

@ixxie
Copy link
Contributor

ixxie commented May 22, 2018

I got this working on my machine, except setting notebookDir to anything but "~/" seems to break the service for some reason.

@phile314-fh
Copy link
Contributor

I have set notebookDir to /var/www/jupyter and it works fine for me. I don't remember though if I created the notebookDir by hand and set the permissions accordingly or if the jupyter service did it automatically.

@ixxie
Copy link
Contributor

ixxie commented May 24, 2018

@phile314-fh - looks like you did it manually. With @cleverca22's help I managed to resolve this by adding:

    serviceConfig.PermissionsStartOnly = true

and

    preStart = ''
      if [ ! -d ${cfg.notebookDir} ]; then
        mkdir -p ${cfg.notebookDir}
      fi
      chown ${cfg.user}:${cfg.group} ${cfg.notebookDir}
    '';

to systemd.services.jupyter.

@aborsu - its probably easiest if you add it yourself to the PR?

@aborsu
Copy link
Contributor Author

aborsu commented May 27, 2018

Hello, sorry, I've been a bit busy.
@FRidh any comments before I start hacking this again?

@ixxie
Copy link
Contributor

ixxie commented May 29, 2018

@aborsu I think I will soon use this as a template to create a Jupyterlab service and it occurred to me that if that would go in nixos/modules/services/development/jupyterlab/default.nix then it would make sense for kernel-options.nix to live somewhere else, maybe:

jupyter/default.nix
jupyterlab/default.nix
jupyterhub/default.nix
jupyterkernels/default.nix      # = kernel-options.nix

Alternatively we can have:

jupyter/
 |-default.nix
 |-kernels/default.nix          #  or just kernel-options.nix
 |-hub/default.nix
 |-lab/default.nix

or is this a bit awkward?

Copy link
Member

@FRidh FRidh left a comment

Choose a reason for hiding this comment

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

I don't really have the time to review this any further, so please ask also other maintainers if they can help it forward / get it in.

env = (pkgs.python3.withPackages (pythonPackages: with pythonPackages; [
ipykernel
pandas
scikitlearn
Copy link
Member

Choose a reason for hiding this comment

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

Keep the default as minimal as possible.


wantedBy = [ "multi-user.target" ];

path = [ pkgs.bash ]; # needed for sh in cell magic to work
Copy link
Member

Choose a reason for hiding this comment

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

Have you considered patching notebook to hardcode bash?


let

jupyterPath = (jupyterKernels.create { kernelDefinitions = kernelDefinitions; });
Copy link
Member

Choose a reason for hiding this comment

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

inherit / space

argv = mkOption {
type = types.listOf types.str;
example = [
"{customEnv}/bin/python"
Copy link
Member

Choose a reason for hiding this comment

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

${customEnv.interpreter}

logo32 = mkOption {
type = types.nullOr types.path;
default = null;
example = "{env}/lib/python3.6/site-packages/ipykernel/resources/logo-32x32.png";
Copy link
Member

Choose a reason for hiding this comment

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

${env.sitePackages}

in

with python3.pkgs; toPythonModule (
notebook.overrideAttrs(oldAttrs: {
Copy link
Member

Choose a reason for hiding this comment

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

overridePythonAttrs

@@ -0,0 +1,76 @@
{ lib, pkgs, stdenv}:
Copy link
Member

Choose a reason for hiding this comment

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

no pkgs, but python3

meta = {
description = "Wrapper to create jupyter notebook kernel definitions";
homepage = http://jupyter.org/;
# NIXOS license as this is a nixos meta package.
Copy link
Member

Choose a reason for hiding this comment

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

No need


src = "/dev/null";

unpackCmd ="mkdir jupyter_kernels";
Copy link
Member

Choose a reason for hiding this comment

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

space


unpackCmd ="mkdir jupyter_kernels";

installPhase = ''
Copy link
Member

Choose a reason for hiding this comment

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

space

@ixxie
Copy link
Contributor

ixxie commented May 29, 2018

@dotlambda perhaps you have time to have a look?

@dotlambda
Copy link
Member

Not until Sunday or even next week, sadly.

@ixxie
Copy link
Contributor

ixxie commented Jun 1, 2018

I was wondering if you could provide a sequence of recent PRs some context and have a Nixpkgs data science workgroup so I made a data science workgroup page on the wiki and #nixos-data on freenode.

@dotlambda
Copy link
Member

@ixxie Please fix the things FRidh mentioned. I'll then take a look. However, I've never worked with Jupyter on NixOS so I might need some time to read through it.

@ixxie
Copy link
Contributor

ixxie commented Jun 6, 2018

@dotlambda well this is @aborsu's PR really and I believe he is on it; if he doesn't have time eventually I can take over, but this is great work and I would hate to steal the credit ;)

I am working on the Jupyterlab module (no PR for that yet).

@teto
Copy link
Member

teto commented Aug 2, 2018

Really looking forward to this. Keep up the good work @aborsu :D

@FRidh
Copy link
Member

FRidh commented Aug 26, 2018

I've made some minor changes and pushed to master 4d3ce5c.

@FRidh FRidh closed this Aug 26, 2018
@teto
Copy link
Member

teto commented Aug 27, 2018

I'll try to give some feedback on the feature, has anyone tried it with an haskell kernel already ?
The jupyter service might deserve a paragraph in the manual (at least a mention in changelog)

@timokau
Copy link
Member

timokau commented Nov 25, 2018

In #51030 I add jupyter support for sage. I've added it so that sage -n jupyter can start a jupyter notebook with the sagemath kernel. I'm not sure how that would integrate with this service, but I've used the kernel spec definition from here and made it available as sage.kernelspec. So if someone wants to integrate that into the jupyter service, that'd be nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants