1{ lib
2, stdenv
3, alembic
4, async-generator
5, beautifulsoup4
6, buildPythonPackage
7, certipy
8, configurable-http-proxy
9, cryptography
10, entrypoints
11, fetchPypi
12, fetchzip
13, importlib-metadata
14, jinja2
15, jsonschema
16, jupyter-telemetry
17, jupyterlab
18, jupyter-core
19, jupyter-server
20, mock
21, nbclassic
22, nodePackages
23, notebook
24, oauthlib
25, packaging
26, pamela
27, playwright
28, prometheus-client
29, pytest-asyncio
30, pytestCheckHook
31, python-dateutil
32, pythonOlder
33, requests
34, requests-mock
35, selenium
36, sqlalchemy
37, tornado
38, traitlets
39, virtualenv
40}:
41
42let
43 # js/css assets that setup.py tries to fetch via `npm install` when building
44 # from source. https://github.com/jupyterhub/jupyterhub/blob/master/package.json
45 bootstrap =
46 fetchzip {
47 url = "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz";
48 sha256 = "1ywmxqdccg0mgx0xknrn1hlrfnhcwphc12y9l91zizx26fqfmzgc";
49 };
50 font-awesome =
51 fetchzip {
52 url = "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz";
53 sha256 = "1xnxbdlfdd60z5ix152m8r2kk9dkwlqwpypky1mm3dv64ajnzdbk";
54 };
55 jquery =
56 fetchzip {
57 url = "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz";
58 sha256 = "0yi9ql493din1qa1s923nd5zvd0klk1sx00xj1wx2yambmq86vm9";
59 };
60 moment =
61 fetchzip {
62 url = "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz";
63 sha256 = "0ifzzla4zffw23g3xvhwx3fj3jny6cjzxfzl1x0317q8wa0c7w5i";
64 };
65 requirejs =
66 fetchzip {
67 url = "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz";
68 sha256 = "165hkli3qcd59cjqvli9r5f92i0h7czkmhcg1cgwamw2d0b7xibz";
69 };
70
71in
72
73buildPythonPackage rec {
74 pname = "jupyterhub";
75 version = "4.0.2";
76 format = "setuptools";
77
78 disabled = pythonOlder "3.7";
79
80 src = fetchPypi {
81 inherit pname version;
82 hash = "sha256-1ORQ7tjZDfvPDsoI8A8gk6C8503FH3z8C3BX9gI0Gh0=";
83 };
84
85 # Most of this only applies when building from source (e.g. js/css assets are
86 # pre-built and bundled in the official release tarball on pypi).
87 #
88 # Stuff that's always needed:
89 # * At runtime, we need configurable-http-proxy, so we substitute the store
90 # path.
91 #
92 # Other stuff that's only needed when building from source:
93 # * js/css assets are fetched from npm.
94 # * substitute store path for `lessc` commmand.
95 # * set up NODE_PATH so `lessc` can find `less-plugin-clean-css`.
96 # * don't run `npm install`.
97 preBuild = ''
98 export NODE_PATH=${nodePackages.less-plugin-clean-css}/lib/node_modules
99
100 substituteInPlace jupyterhub/proxy.py --replace \
101 "'configurable-http-proxy'" \
102 "'${configurable-http-proxy}/bin/configurable-http-proxy'"
103
104 substituteInPlace jupyterhub/tests/test_proxy.py --replace \
105 "'configurable-http-proxy'" \
106 "'${configurable-http-proxy}/bin/configurable-http-proxy'"
107
108 substituteInPlace setup.py --replace \
109 "'npm'" "'true'"
110
111 declare -A deps
112 deps[bootstrap]=${bootstrap}
113 deps[font-awesome]=${font-awesome}
114 deps[jquery]=${jquery}
115 deps[moment]=${moment}
116 deps[requirejs]=${requirejs}
117
118 mkdir -p share/jupyter/hub/static/components
119 for dep in "''${!deps[@]}"; do
120 if [ ! -e share/jupyter/hub/static/components/$dep ]; then
121 cp -r ''${deps[$dep]} share/jupyter/hub/static/components/$dep
122 fi
123 done
124 '';
125
126 propagatedBuildInputs = [
127 alembic
128 async-generator
129 certipy
130 python-dateutil
131 entrypoints
132 jinja2
133 jupyter-telemetry
134 oauthlib
135 packaging
136 pamela
137 prometheus-client
138 requests
139 selenium
140 sqlalchemy
141 tornado
142 traitlets
143 jupyter-core
144 jupyter-server
145 ] ++ lib.optionals (pythonOlder "3.10") [
146 importlib-metadata
147 ];
148
149 nativeCheckInputs = [
150 beautifulsoup4
151 cryptography
152 notebook
153 jsonschema
154 nbclassic
155 mock
156 jupyterlab
157 playwright
158 pytest-asyncio
159 pytestCheckHook
160 requests-mock
161 virtualenv
162 ];
163
164 preCheck = ''
165 substituteInPlace jupyterhub/tests/test_spawner.py --replace \
166 "'jupyterhub-singleuser'" "'$out/bin/jupyterhub-singleuser'"
167 export PATH="$PATH:$out/bin";
168 '';
169
170 disabledTests = [
171 # Tries to install older versions through pip
172 "test_upgrade"
173 # Testcase fails to find requests import
174 "test_external_service"
175 # Attempts to do TLS connection
176 "test_connection_notebook_wrong_certs"
177 # AttributeError: 'coroutine' object...
178 "test_valid_events"
179 "test_invalid_events"
180 "test_user_group_roles"
181 ];
182
183 disabledTestPaths = [
184 # Not testing with a running instance
185 # AttributeError: 'coroutine' object has no attribute 'db'
186 "docs/test_docs.py"
187 "jupyterhub/tests/browser/test_browser.py"
188 "jupyterhub/tests/test_api.py"
189 "jupyterhub/tests/test_auth_expiry.py"
190 "jupyterhub/tests/test_auth.py"
191 "jupyterhub/tests/test_metrics.py"
192 "jupyterhub/tests/test_named_servers.py"
193 "jupyterhub/tests/test_orm.py"
194 "jupyterhub/tests/test_pages.py"
195 "jupyterhub/tests/test_proxy.py"
196 "jupyterhub/tests/test_scopes.py"
197 "jupyterhub/tests/test_services_auth.py"
198 "jupyterhub/tests/test_singleuser.py"
199 "jupyterhub/tests/test_spawner.py"
200 "jupyterhub/tests/test_user.py"
201 ];
202
203 meta = with lib; {
204 description = "Serves multiple Jupyter notebook instances";
205 homepage = "https://jupyter.org/";
206 changelog = "https://github.com/jupyterhub/jupyterhub/blob/${version}/docs/source/reference/changelog.md";
207 license = licenses.bsd3;
208 maintainers = with maintainers; [ ixxie ];
209 # darwin: E OSError: dlopen(/nix/store/43zml0mlr17r5jsagxr00xxx91hz9lky-openpam-20170430/lib/libpam.so, 6): image not found
210 broken = (stdenv.isLinux && stdenv.isAarch64) || stdenv.isDarwin;
211 };
212}