jupyverse 0.0.50__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jupyverse-0.0.50 → jupyverse-0.1.2}/.github/workflows/check-release.yml +3 -1
- {jupyverse-0.0.50 → jupyverse-0.1.2}/.pre-commit-config.yaml +5 -15
- {jupyverse-0.0.50 → jupyverse-0.1.2}/CHANGELOG.md +45 -2
- {jupyverse-0.0.50 → jupyverse-0.1.2}/PKG-INFO +19 -16
- {jupyverse-0.0.50 → jupyverse-0.1.2}/binder/jupyter_notebook_config.py +8 -10
- {jupyverse-0.0.50 → jupyverse-0.1.2}/binder/postBuild +1 -0
- jupyverse-0.1.2/config.yaml +52 -0
- jupyverse-0.1.2/docs/install.md +119 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/auth.md +8 -19
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/usage/multi_user.md +5 -5
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/usage/single_user.md +6 -6
- jupyverse-0.1.2/jupyverse/__init__.py +1 -0
- jupyverse-0.1.2/jupyverse/cli.py +97 -0
- jupyverse-0.1.2/jupyverse_api/README.md +3 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/__init__.py +42 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/app/__init__.py +51 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/auth/__init__.py +27 -0
- {jupyverse-0.0.50/plugins/noauth/fps_noauth → jupyverse-0.1.2/jupyverse_api/jupyverse_api/auth}/models.py +0 -2
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/contents/__init__.py +38 -0
- {jupyverse-0.0.50/plugins/contents/fps_contents → jupyverse-0.1.2/jupyverse_api/jupyverse_api/contents}/models.py +7 -22
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/exceptions.py +11 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/frontend/__init__.py +6 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/jupyterlab/__init__.py +9 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/kernels/__init__.py +16 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/lab/__init__.py +18 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/login/__init__.py +5 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/main/__init__.py +80 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/nbconvert/__init__.py +5 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/resource_usage/__init__.py +13 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/retrolab/__init__.py +5 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/terminals/__init__.py +16 -0
- jupyverse-0.1.2/jupyverse_api/jupyverse_api/yjs/__init__.py +7 -0
- jupyverse-0.1.2/jupyverse_api/pyproject.toml +45 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/mkdocs.yml +11 -12
- jupyverse-0.1.2/plugins/auth/fps_auth/__init__.py +1 -0
- jupyverse-0.1.2/plugins/auth/fps_auth/backends.py +285 -0
- jupyverse-0.1.2/plugins/auth/fps_auth/config.py +18 -0
- jupyverse-0.1.2/plugins/auth/fps_auth/db.py +98 -0
- jupyverse-0.1.2/plugins/auth/fps_auth/main.py +69 -0
- jupyverse-0.1.2/plugins/auth/fps_auth/models.py +22 -0
- jupyverse-0.1.2/plugins/auth/fps_auth/routes.py +150 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/auth/pyproject.toml +5 -15
- jupyverse-0.1.2/plugins/auth_fief/fps_auth_fief/__init__.py +1 -0
- jupyverse-0.1.2/plugins/auth_fief/fps_auth_fief/backend.py +96 -0
- jupyverse-0.1.2/plugins/auth_fief/fps_auth_fief/config.py +7 -0
- jupyverse-0.1.2/plugins/auth_fief/fps_auth_fief/main.py +22 -0
- jupyverse-0.1.2/plugins/auth_fief/fps_auth_fief/routes.py +73 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/auth_fief/pyproject.toml +5 -13
- jupyverse-0.1.2/plugins/contents/fps_contents/__init__.py +1 -0
- jupyverse-0.1.2/plugins/contents/fps_contents/fileid.py +207 -0
- jupyverse-0.1.2/plugins/contents/fps_contents/main.py +18 -0
- jupyverse-0.1.2/plugins/contents/fps_contents/models.py +18 -0
- jupyverse-0.1.2/plugins/contents/fps_contents/routes.py +288 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/contents/pyproject.toml +10 -4
- jupyverse-0.1.2/plugins/frontend/fps_frontend/__init__.py +1 -0
- jupyverse-0.1.2/plugins/frontend/fps_frontend/main.py +13 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/frontend/pyproject.toml +7 -4
- jupyverse-0.1.2/plugins/jupyterlab/fps_jupyterlab/__init__.py +1 -0
- jupyverse-0.1.2/plugins/jupyterlab/fps_jupyterlab/index.py +32 -0
- jupyverse-0.1.2/plugins/jupyterlab/fps_jupyterlab/main.py +27 -0
- jupyverse-0.1.2/plugins/jupyterlab/fps_jupyterlab/py.typed +0 -0
- jupyverse-0.1.2/plugins/jupyterlab/fps_jupyterlab/routes.py +177 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/jupyterlab/pyproject.toml +8 -7
- jupyverse-0.1.2/plugins/kernels/fps_kernels/__init__.py +1 -0
- jupyverse-0.1.2/plugins/kernels/fps_kernels/kernel_driver/__init__.py +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/kernels/fps_kernels/kernel_driver/driver.py +2 -2
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/kernels/fps_kernels/kernel_driver/message.py +1 -1
- jupyverse-0.1.2/plugins/kernels/fps_kernels/kernel_server/__init__.py +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/kernels/fps_kernels/kernel_server/server.py +6 -3
- jupyverse-0.1.2/plugins/kernels/fps_kernels/main.py +50 -0
- jupyverse-0.1.2/plugins/kernels/fps_kernels/routes.py +364 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/kernels/pyproject.toml +12 -7
- jupyverse-0.1.2/plugins/lab/fps_lab/__init__.py +1 -0
- jupyverse-0.1.2/plugins/lab/fps_lab/main.py +22 -0
- jupyverse-0.1.2/plugins/lab/fps_lab/routes.py +253 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/lab/pyproject.toml +9 -7
- jupyverse-0.1.2/plugins/login/fps_login/__init__.py +1 -0
- jupyverse-0.1.2/plugins/login/fps_login/main.py +18 -0
- jupyverse-0.1.2/plugins/login/fps_login/routes.py +41 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/pyproject.toml +7 -4
- jupyverse-0.1.2/plugins/nbconvert/fps_nbconvert/__init__.py +1 -0
- jupyverse-0.1.2/plugins/nbconvert/fps_nbconvert/main.py +18 -0
- jupyverse-0.1.2/plugins/nbconvert/fps_nbconvert/routes.py +47 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/nbconvert/pyproject.toml +8 -4
- jupyverse-0.1.2/plugins/noauth/fps_noauth/__init__.py +1 -0
- jupyverse-0.1.2/plugins/noauth/fps_noauth/backends.py +32 -0
- jupyverse-0.1.2/plugins/noauth/fps_noauth/main.py +13 -0
- jupyverse-0.1.2/plugins/noauth/fps_noauth/py.typed +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/noauth/pyproject.toml +8 -7
- jupyverse-0.1.2/plugins/resource_usage/fps_resource_usage/__init__.py +1 -0
- jupyverse-0.1.2/plugins/resource_usage/fps_resource_usage/main.py +21 -0
- jupyverse-0.1.2/plugins/resource_usage/fps_resource_usage/routes.py +74 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/resource_usage/pyproject.toml +10 -7
- jupyverse-0.1.2/plugins/retrolab/fps_retrolab/__init__.py +1 -0
- jupyverse-0.1.2/plugins/retrolab/fps_retrolab/main.py +22 -0
- jupyverse-0.1.2/plugins/retrolab/fps_retrolab/routes.py +170 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/retrolab/pyproject.toml +8 -7
- jupyverse-0.1.2/plugins/terminals/fps_terminals/__init__.py +1 -0
- jupyverse-0.1.2/plugins/terminals/fps_terminals/main.py +27 -0
- jupyverse-0.1.2/plugins/terminals/fps_terminals/routes.py +66 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/terminals/fps_terminals/server.py +2 -1
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/terminals/fps_terminals/win_server.py +2 -1
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/terminals/pyproject.toml +10 -5
- jupyverse-0.1.2/plugins/yjs/fps_yjs/__init__.py +1 -0
- jupyverse-0.1.2/plugins/yjs/fps_yjs/main.py +33 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/yjs/fps_yjs/models.py +1 -1
- jupyverse-0.1.2/plugins/yjs/fps_yjs/py.typed +0 -0
- jupyverse-0.1.2/plugins/yjs/fps_yjs/routes.py +360 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/yjs/pyproject.toml +7 -8
- {jupyverse-0.0.50 → jupyverse-0.1.2}/pyproject.toml +60 -43
- jupyverse-0.1.2/tests/conftest.py +40 -0
- jupyverse-0.1.2/tests/test_auth.py +132 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/tests/test_contents.py +33 -11
- jupyverse-0.1.2/tests/test_kernels.py +102 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/tests/test_server.py +5 -4
- jupyverse-0.1.2/tests/test_settings.py +58 -0
- jupyverse-0.1.2/tests/utils.py +120 -0
- jupyverse-0.0.50/docs/install.md +0 -97
- jupyverse-0.0.50/docs/plugins/fps.md +0 -44
- jupyverse-0.0.50/jupyverse/__init__.py +0 -1
- jupyverse-0.0.50/plugins/__init__.py +0 -2
- jupyverse-0.0.50/plugins/auth/fps_auth/__init__.py +0 -1
- jupyverse-0.0.50/plugins/auth/fps_auth/backends.py +0 -268
- jupyverse-0.0.50/plugins/auth/fps_auth/config.py +0 -30
- jupyverse-0.0.50/plugins/auth/fps_auth/db.py +0 -79
- jupyverse-0.0.50/plugins/auth/fps_auth/fixtures.py +0 -84
- jupyverse-0.0.50/plugins/auth/fps_auth/models.py +0 -33
- jupyverse-0.0.50/plugins/auth/fps_auth/routes.py +0 -171
- jupyverse-0.0.50/plugins/auth_base/README.md +0 -3
- jupyverse-0.0.50/plugins/auth_base/fps_auth_base/__init__.py +0 -15
- jupyverse-0.0.50/plugins/auth_base/pyproject.toml +0 -34
- jupyverse-0.0.50/plugins/auth_fief/fps_auth_fief/__init__.py +0 -1
- jupyverse-0.0.50/plugins/auth_fief/fps_auth_fief/backend.py +0 -92
- jupyverse-0.0.50/plugins/auth_fief/fps_auth_fief/config.py +0 -23
- jupyverse-0.0.50/plugins/auth_fief/fps_auth_fief/models.py +0 -18
- jupyverse-0.0.50/plugins/auth_fief/fps_auth_fief/routes.py +0 -62
- jupyverse-0.0.50/plugins/contents/fps_contents/__init__.py +0 -1
- jupyverse-0.0.50/plugins/contents/fps_contents/fileid.py +0 -192
- jupyverse-0.0.50/plugins/contents/fps_contents/routes.py +0 -280
- jupyverse-0.0.50/plugins/frontend/fps_frontend/__init__.py +0 -1
- jupyverse-0.0.50/plugins/frontend/fps_frontend/config.py +0 -13
- jupyverse-0.0.50/plugins/jupyterlab/fps_jupyterlab/__init__.py +0 -1
- jupyverse-0.0.50/plugins/jupyterlab/fps_jupyterlab/config.py +0 -13
- jupyverse-0.0.50/plugins/jupyterlab/fps_jupyterlab/routes.py +0 -207
- jupyverse-0.0.50/plugins/kernels/fps_kernels/__init__.py +0 -1
- jupyverse-0.0.50/plugins/kernels/fps_kernels/config.py +0 -16
- jupyverse-0.0.50/plugins/kernels/fps_kernels/routes.py +0 -339
- jupyverse-0.0.50/plugins/lab/fps_lab/__init__.py +0 -1
- jupyverse-0.0.50/plugins/lab/fps_lab/config.py +0 -13
- jupyverse-0.0.50/plugins/lab/fps_lab/routes.py +0 -215
- jupyverse-0.0.50/plugins/lab/fps_lab/utils.py +0 -25
- jupyverse-0.0.50/plugins/login/fps_login/__init__.py +0 -1
- jupyverse-0.0.50/plugins/login/fps_login/routes.py +0 -30
- jupyverse-0.0.50/plugins/nbconvert/fps_nbconvert/__init__.py +0 -1
- jupyverse-0.0.50/plugins/nbconvert/fps_nbconvert/routes.py +0 -40
- jupyverse-0.0.50/plugins/noauth/fps_noauth/__init__.py +0 -1
- jupyverse-0.0.50/plugins/noauth/fps_noauth/backends.py +0 -34
- jupyverse-0.0.50/plugins/resource_usage/fps_resource_usage/__init__.py +0 -1
- jupyverse-0.0.50/plugins/resource_usage/fps_resource_usage/config.py +0 -18
- jupyverse-0.0.50/plugins/resource_usage/fps_resource_usage/routes.py +0 -65
- jupyverse-0.0.50/plugins/retrolab/fps_retrolab/__init__.py +0 -1
- jupyverse-0.0.50/plugins/retrolab/fps_retrolab/config.py +0 -13
- jupyverse-0.0.50/plugins/retrolab/fps_retrolab/routes.py +0 -176
- jupyverse-0.0.50/plugins/terminals/fps_terminals/__init__.py +0 -1
- jupyverse-0.0.50/plugins/terminals/fps_terminals/routes.py +0 -70
- jupyverse-0.0.50/plugins/yjs/MANIFEST.in +0 -1
- jupyverse-0.0.50/plugins/yjs/fps_yjs/__init__.py +0 -1
- jupyverse-0.0.50/plugins/yjs/fps_yjs/routes.py +0 -335
- jupyverse-0.0.50/tests/conftest.py +0 -53
- jupyverse-0.0.50/tests/test_auth.py +0 -67
- jupyverse-0.0.50/tests/test_kernels.py +0 -78
- jupyverse-0.0.50/tests/test_settings.py +0 -29
- jupyverse-0.0.50/tests/utils.py +0 -53
- {jupyverse-0.0.50 → jupyverse-0.1.2}/.devcontainer/devcontainer.json +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/.devcontainer/requirements.txt +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/.github/workflows/main.yml +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/.gitignore +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/CONTRIBUTING.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/COPYING.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/binder/environment.yml +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/binder/start +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/index.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/jupyter.svg +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/contents.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/frontend.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/jupyterlab.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/kernels.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/lab.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/login.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/nbconvert.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/resource_usage.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/retrolab.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/terminals.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/docs/plugins/yjs.md +0 -0
- {jupyverse-0.0.50/plugins/auth_base/fps_auth_base → jupyverse-0.1.2/jupyverse}/py.typed +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/jupyverse/static/favicon.ico +0 -0
- {jupyverse-0.0.50/plugins/auth → jupyverse-0.1.2/jupyverse_api}/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/kernels/fps_kernels → jupyverse-0.1.2/jupyverse_api/jupyverse_api/kernels}/models.py +0 -0
- {jupyverse-0.0.50/plugins/contents/fps_contents → jupyverse-0.1.2/jupyverse_api/jupyverse_api}/py.typed +0 -0
- {jupyverse-0.0.50/plugins/auth_base → jupyverse-0.1.2/plugins/auth}/COPYING.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/auth/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/auth/README.md +0 -0
- {jupyverse-0.0.50/plugins/noauth/fps_noauth → jupyverse-0.1.2/plugins/auth/fps_auth}/py.typed +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/auth_fief/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/auth_base → jupyverse-0.1.2/plugins/auth_fief}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/auth_fief/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/contents/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/auth_fief → jupyverse-0.1.2/plugins/contents}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/contents/README.md +0 -0
- /jupyverse-0.0.50/plugins/kernels/fps_kernels/kernel_driver/__init__.py → /jupyverse-0.1.2/plugins/contents/fps_contents/py.typed +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/frontend/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/contents → jupyverse-0.1.2/plugins/frontend}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/frontend/README.md +0 -0
- /jupyverse-0.0.50/plugins/kernels/fps_kernels/kernel_server/__init__.py → /jupyverse-0.1.2/plugins/frontend/fps_frontend/py.typed +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/jupyterlab/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/frontend → jupyverse-0.1.2/plugins/jupyterlab}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/jupyterlab/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/kernels/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/jupyterlab → jupyverse-0.1.2/plugins/kernels}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/kernels/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/kernels/fps_kernels/kernel_driver/connect.py +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/kernels/fps_kernels/kernel_driver/kernelspec.py +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/kernels/fps_kernels/kernel_driver/paths.py +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/kernels/fps_kernels/kernel_server/message.py +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/lab/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/kernels → jupyverse-0.1.2/plugins/lab}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/lab/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/COPYING.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/fps_login/static/favicons/favicon-busy-1.ico +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/fps_login/static/favicons/favicon-busy-2.ico +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/fps_login/static/favicons/favicon-busy-3.ico +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/fps_login/static/favicons/favicon-file.ico +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/fps_login/static/favicons/favicon-notebook.ico +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/fps_login/static/favicons/favicon-terminal.ico +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/fps_login/static/favicons/favicon.ico +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/fps_login/static/index.html +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/fps_login/static/logo/github.svg +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/fps_login/static/logo/logo.png +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/login/fps_login/static/style/index.css +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/nbconvert/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/lab → jupyverse-0.1.2/plugins/nbconvert}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/nbconvert/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/noauth/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/nbconvert → jupyverse-0.1.2/plugins/noauth}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/noauth/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/resource_usage/COPYING.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/resource_usage/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/retrolab/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/noauth → jupyverse-0.1.2/plugins/retrolab}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/retrolab/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/terminals/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/retrolab → jupyverse-0.1.2/plugins/terminals}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/terminals/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/terminals/fps_terminals/models.py +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/yjs/COPYING.md +0 -0
- {jupyverse-0.0.50/plugins/terminals → jupyverse-0.1.2/plugins/yjs}/MANIFEST.in +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/plugins/yjs/README.md +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/pytest.ini +0 -0
- {jupyverse-0.0.50 → jupyverse-0.1.2}/tests/data/notebook0.ipynb +0 -0
@@ -44,7 +44,7 @@ jobs:
|
|
44
44
|
- name: Install Dependencies
|
45
45
|
run: |
|
46
46
|
pip install -e . --no-deps
|
47
|
-
pip install -e
|
47
|
+
pip install -e jupyverse_api
|
48
48
|
pip install -e plugins/frontend
|
49
49
|
pip install -e plugins/jupyterlab
|
50
50
|
pip install -e plugins/retrolab
|
@@ -54,6 +54,8 @@ jobs:
|
|
54
54
|
pip install -e plugins/nbconvert
|
55
55
|
pip install -e plugins/yjs
|
56
56
|
pip install -e plugins/auth
|
57
|
+
pip install -e plugins/noauth
|
58
|
+
pip install -e plugins/auth_fief
|
57
59
|
pip install -e plugins/login
|
58
60
|
- name: Check Release
|
59
61
|
if: ${{ matrix.group == 'check_release' }}
|
@@ -16,22 +16,12 @@ repos:
|
|
16
16
|
- id: trailing-whitespace
|
17
17
|
|
18
18
|
- repo: https://github.com/psf/black
|
19
|
-
rev: 23.
|
19
|
+
rev: 23.3.0
|
20
20
|
hooks:
|
21
21
|
- id: black
|
22
|
-
args: ["--line-length", "100"]
|
23
22
|
|
24
|
-
- repo: https://github.com/
|
25
|
-
rev:
|
23
|
+
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
24
|
+
rev: v0.0.260
|
26
25
|
hooks:
|
27
|
-
- id:
|
28
|
-
|
29
|
-
args: [--profile=black]
|
30
|
-
|
31
|
-
- repo: https://github.com/pycqa/flake8
|
32
|
-
rev: 6.0.0
|
33
|
-
hooks:
|
34
|
-
- id: flake8
|
35
|
-
exclude: binder
|
36
|
-
additional_dependencies:
|
37
|
-
["flake8-implicit-str-concat==0.2.0", "flake8-pyproject"]
|
26
|
+
- id: ruff
|
27
|
+
args: ["--fix"]
|
@@ -2,6 +2,51 @@
|
|
2
2
|
|
3
3
|
<!-- <START NEW CHANGELOG ENTRY> -->
|
4
4
|
|
5
|
+
## 0.1.2
|
6
|
+
|
7
|
+
No merged PRs
|
8
|
+
|
9
|
+
<!-- <END NEW CHANGELOG ENTRY> -->
|
10
|
+
|
11
|
+
## 0.1.1
|
12
|
+
|
13
|
+
([Full Changelog](https://github.com/jupyter-server/jupyverse/compare/v0.0.50...254a3dfd5f6851e2e79406fab934c8361399ffb6))
|
14
|
+
|
15
|
+
### Merged PRs
|
16
|
+
|
17
|
+
- Fix jupyverse-api -> jupyverse_api [#286](https://github.com/jupyter-server/jupyverse/pull/286) ([@davidbrochart](https://github.com/davidbrochart))
|
18
|
+
- Add jupyverse_api dependency to plugins [#285](https://github.com/jupyter-server/jupyverse/pull/285) ([@davidbrochart](https://github.com/davidbrochart))
|
19
|
+
- Update documentation, add jupyverse CLI [#283](https://github.com/jupyter-server/jupyverse/pull/283) ([@davidbrochart](https://github.com/davidbrochart))
|
20
|
+
- Update to FastAPI 0.95 [#281](https://github.com/jupyter-server/jupyverse/pull/281) ([@davidbrochart](https://github.com/davidbrochart))
|
21
|
+
- Drop FPS in favor of Asphalt [#277](https://github.com/jupyter-server/jupyverse/pull/277) ([@davidbrochart](https://github.com/davidbrochart))
|
22
|
+
- Add ruff pre-commit [#275](https://github.com/jupyter-server/jupyverse/pull/275) ([@davidbrochart](https://github.com/davidbrochart))
|
23
|
+
- Add DELETE /api/kernels/{kernel_id} (shutdown kernel) [#274](https://github.com/jupyter-server/jupyverse/pull/274) ([@davidbrochart](https://github.com/davidbrochart))
|
24
|
+
|
25
|
+
### Contributors to this release
|
26
|
+
|
27
|
+
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyverse/graphs/contributors?from=2023-02-23&to=2023-04-06&type=c))
|
28
|
+
|
29
|
+
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyverse+involves%3Adavidbrochart+updated%3A2023-02-23..2023-04-06&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyverse+involves%3Apre-commit-ci+updated%3A2023-02-23..2023-04-06&type=Issues)
|
30
|
+
|
31
|
+
## 0.1.0
|
32
|
+
|
33
|
+
([Full Changelog](https://github.com/jupyter-server/jupyverse/compare/v0.0.50...62b06f7a05b4ba536ce1ae0f40b3643dc4b4152d))
|
34
|
+
|
35
|
+
### Merged PRs
|
36
|
+
|
37
|
+
- Add jupyverse_api dependency to plugins [#285](https://github.com/jupyter-server/jupyverse/pull/285) ([@davidbrochart](https://github.com/davidbrochart))
|
38
|
+
- Update documentation, add jupyverse CLI [#283](https://github.com/jupyter-server/jupyverse/pull/283) ([@davidbrochart](https://github.com/davidbrochart))
|
39
|
+
- Update to FastAPI 0.95 [#281](https://github.com/jupyter-server/jupyverse/pull/281) ([@davidbrochart](https://github.com/davidbrochart))
|
40
|
+
- Drop FPS in favor of Asphalt [#277](https://github.com/jupyter-server/jupyverse/pull/277) ([@davidbrochart](https://github.com/davidbrochart))
|
41
|
+
- Add ruff pre-commit [#275](https://github.com/jupyter-server/jupyverse/pull/275) ([@davidbrochart](https://github.com/davidbrochart))
|
42
|
+
- Add DELETE /api/kernels/{kernel_id} (shutdown kernel) [#274](https://github.com/jupyter-server/jupyverse/pull/274) ([@davidbrochart](https://github.com/davidbrochart))
|
43
|
+
|
44
|
+
### Contributors to this release
|
45
|
+
|
46
|
+
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyverse/graphs/contributors?from=2023-02-23&to=2023-04-06&type=c))
|
47
|
+
|
48
|
+
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyverse+involves%3Adavidbrochart+updated%3A2023-02-23..2023-04-06&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyverse+involves%3Apre-commit-ci+updated%3A2023-02-23..2023-04-06&type=Issues)
|
49
|
+
|
5
50
|
## 0.0.50
|
6
51
|
|
7
52
|
([Full Changelog](https://github.com/jupyter-server/jupyverse/compare/v0.0.49...cf56682249dd5c7064d16b4a88f6f49aeb728ce1))
|
@@ -17,8 +62,6 @@
|
|
17
62
|
|
18
63
|
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyverse+involves%3Adavidbrochart+updated%3A2023-01-24..2023-02-23&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyverse+involves%3Apre-commit-ci+updated%3A2023-01-24..2023-02-23&type=Issues)
|
19
64
|
|
20
|
-
<!-- <END NEW CHANGELOG ENTRY> -->
|
21
|
-
|
22
65
|
## 0.0.49
|
23
66
|
|
24
67
|
([Full Changelog](https://github.com/jupyter-server/jupyverse/compare/v0.0.48...c976ab4f7c7c8c416b19dc794f253ec0a2c87636))
|
@@ -1,36 +1,39 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: jupyverse
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.1.2
|
4
4
|
Summary: A set of FPS plugins implementing a Jupyter server
|
5
5
|
Project-URL: Homepage, https://jupyter.org
|
6
6
|
Author-email: Jupyter Development Team <jupyter@googlegroups.com>
|
7
7
|
License: BSD 3-Clause License
|
8
8
|
License-File: COPYING.md
|
9
|
-
Keywords: fastapi,jupyter,
|
9
|
+
Keywords: fastapi,jupyter,plugins,server
|
10
10
|
Requires-Python: >=3.8
|
11
|
-
Requires-Dist: fastapi
|
12
|
-
Requires-Dist:
|
13
|
-
Requires-Dist:
|
14
|
-
Requires-Dist: fps-
|
15
|
-
Requires-Dist: fps-
|
16
|
-
Requires-Dist: fps-
|
17
|
-
Requires-Dist: fps-
|
18
|
-
Requires-Dist: fps-yjs
|
19
|
-
Requires-Dist:
|
11
|
+
Requires-Dist: asphalt-web[fastapi]<2,>=1.1.0
|
12
|
+
Requires-Dist: asphalt<5,>=4.11.0
|
13
|
+
Requires-Dist: fastapi<1,>=0.95.0
|
14
|
+
Requires-Dist: fps-contents
|
15
|
+
Requires-Dist: fps-kernels
|
16
|
+
Requires-Dist: fps-nbconvert
|
17
|
+
Requires-Dist: fps-terminals
|
18
|
+
Requires-Dist: fps-yjs
|
19
|
+
Requires-Dist: jupyverse-api
|
20
|
+
Requires-Dist: rich-click<2,>=1.6.1
|
20
21
|
Provides-Extra: auth
|
21
|
-
Requires-Dist: fps-auth
|
22
|
+
Requires-Dist: fps-auth; extra == 'auth'
|
22
23
|
Provides-Extra: auth-fief
|
23
|
-
Requires-Dist: fps-auth-fief
|
24
|
+
Requires-Dist: fps-auth-fief; extra == 'auth-fief'
|
24
25
|
Provides-Extra: docs
|
25
26
|
Requires-Dist: mkdocs; extra == 'docs'
|
26
27
|
Requires-Dist: mkdocs-material; extra == 'docs'
|
27
28
|
Provides-Extra: jupyterlab
|
28
|
-
Requires-Dist: fps-jupyterlab
|
29
|
+
Requires-Dist: fps-jupyterlab; extra == 'jupyterlab'
|
29
30
|
Provides-Extra: noauth
|
30
|
-
Requires-Dist: fps-noauth
|
31
|
+
Requires-Dist: fps-noauth; extra == 'noauth'
|
31
32
|
Provides-Extra: retrolab
|
32
|
-
Requires-Dist: fps-retrolab
|
33
|
+
Requires-Dist: fps-retrolab; extra == 'retrolab'
|
33
34
|
Provides-Extra: test
|
35
|
+
Requires-Dist: httpx; extra == 'test'
|
36
|
+
Requires-Dist: httpx-ws; extra == 'test'
|
34
37
|
Requires-Dist: ipykernel; extra == 'test'
|
35
38
|
Requires-Dist: mypy; extra == 'test'
|
36
39
|
Requires-Dist: pytest; extra == 'test'
|
@@ -1,11 +1,10 @@
|
|
1
1
|
jupyverse_jlab_command = " ".join(
|
2
2
|
[
|
3
3
|
"jupyverse",
|
4
|
-
"--
|
5
|
-
"--
|
6
|
-
"--
|
7
|
-
"--retrolab
|
8
|
-
"--lab.base_url={base_url}jupyverse-jlab/",
|
4
|
+
"--set auth.mode=noauth",
|
5
|
+
"--set frontend.collaborative=true",
|
6
|
+
"--set frontend.base_url={base_url}jupyverse-jlab/",
|
7
|
+
"--disable retrolab",
|
9
8
|
"--port={port}",
|
10
9
|
]
|
11
10
|
+ [">jupyverse_jlab.log 2>&1"]
|
@@ -15,11 +14,10 @@ jupyverse_jlab_command = " ".join(
|
|
15
14
|
jupyverse_rlab_command = " ".join(
|
16
15
|
[
|
17
16
|
"jupyverse",
|
18
|
-
"--
|
19
|
-
"--
|
20
|
-
"--
|
21
|
-
"--jupyterlab
|
22
|
-
"--lab.base_url={base_url}jupyverse-rlab/",
|
17
|
+
"--set auth.mode=noauth",
|
18
|
+
"--set frontend.collaborative=true",
|
19
|
+
"--set frontend.base_url={base_url}jupyverse-rlab/",
|
20
|
+
"--disable jupyterlab",
|
23
21
|
"--port={port}",
|
24
22
|
]
|
25
23
|
+ [">jupyverse_rlab.log 2>&1"]
|
@@ -0,0 +1,52 @@
|
|
1
|
+
---
|
2
|
+
component:
|
3
|
+
type: jupyverse
|
4
|
+
components:
|
5
|
+
app:
|
6
|
+
type: app
|
7
|
+
auth:
|
8
|
+
type: auth
|
9
|
+
#auth:
|
10
|
+
# type: auth_fief
|
11
|
+
#auth:
|
12
|
+
# type: noauth
|
13
|
+
contents:
|
14
|
+
type: contents
|
15
|
+
frontend:
|
16
|
+
type: frontend
|
17
|
+
lab:
|
18
|
+
type: lab
|
19
|
+
jupyterlab:
|
20
|
+
type: jupyterlab
|
21
|
+
kernels:
|
22
|
+
type: kernels
|
23
|
+
login:
|
24
|
+
type: login
|
25
|
+
nbconvert:
|
26
|
+
type: nbconvert
|
27
|
+
resource_usage:
|
28
|
+
type: resource_usage
|
29
|
+
track_cpu_percent: true
|
30
|
+
#retrolab:
|
31
|
+
# type: retrolab
|
32
|
+
terminals:
|
33
|
+
type: terminals
|
34
|
+
yjs:
|
35
|
+
type: yjs
|
36
|
+
|
37
|
+
logging:
|
38
|
+
version: 1
|
39
|
+
disable_existing_loggers: false
|
40
|
+
formatters:
|
41
|
+
default:
|
42
|
+
format: '[%(asctime)s %(levelname)s] %(message)s'
|
43
|
+
handlers:
|
44
|
+
console:
|
45
|
+
class: logging.StreamHandler
|
46
|
+
formatter: default
|
47
|
+
root:
|
48
|
+
handlers: [console]
|
49
|
+
level: INFO
|
50
|
+
loggers:
|
51
|
+
webnotifier:
|
52
|
+
level: DEBUG
|
@@ -0,0 +1,119 @@
|
|
1
|
+
Jupyverse can be installed to run either [JupyterLab](https://jupyterlab.readthedocs.io) or [RetroLab](https://github.com/jupyterlab/retrolab).
|
2
|
+
|
3
|
+
## With `pip`
|
4
|
+
|
5
|
+
For the JupyterLab frontend:
|
6
|
+
```bash
|
7
|
+
pip install "jupyverse[jupyterlab,auth]"
|
8
|
+
```
|
9
|
+
Or for the RetroLab frontend:
|
10
|
+
```bash
|
11
|
+
pip install "jupyverse[retrolab,auth]"
|
12
|
+
```
|
13
|
+
|
14
|
+
## With `micromamba`
|
15
|
+
|
16
|
+
We recommend using `micromamba` to manage [conda-forge](https://conda-forge.org) environments
|
17
|
+
(see `micromamba`'s
|
18
|
+
[installation instructions](https://mamba.readthedocs.io/en/latest/installation.html#micromamba)).
|
19
|
+
First create an environment, here called `jupyverse`, and activate it:
|
20
|
+
```bash
|
21
|
+
micromamba create -n jupyverse
|
22
|
+
micromamba activate jupyverse
|
23
|
+
```
|
24
|
+
Then install Jupyverse and the desired plugins.
|
25
|
+
|
26
|
+
For the JupyterLab frontend:
|
27
|
+
```bash
|
28
|
+
micromamba install -c conda-forge jupyverse fps-jupyterlab fps-auth
|
29
|
+
```
|
30
|
+
Or for the RetroLab frontend:
|
31
|
+
```bash
|
32
|
+
micromamba install -c conda-forge jupyverse fps-retrolab fps-auth
|
33
|
+
```
|
34
|
+
|
35
|
+
## Development install
|
36
|
+
|
37
|
+
You first need to clone the repository:
|
38
|
+
```bash
|
39
|
+
git clone https://github.com/jupyter-server/jupyverse.git
|
40
|
+
cd jupyverse
|
41
|
+
```
|
42
|
+
Jupyverse uses [Hatch](https://github.com/pypa/hatch) for project management.
|
43
|
+
Hatch can handle multiple environments in parallel, allowing for easy development
|
44
|
+
and testing of different frontends, authentication methods, and incompatible
|
45
|
+
plugins.
|
46
|
+
|
47
|
+
We recommend working in an isolated conda environment, in which hatch will manage
|
48
|
+
sub-environments:
|
49
|
+
```bash
|
50
|
+
micromamba create -n jupyverse-dev
|
51
|
+
micromamba activate jupyverse-dev
|
52
|
+
micromamba install -c conda-forge hatch
|
53
|
+
```
|
54
|
+
Entering `hatch env show` will show the available environments:
|
55
|
+
```text
|
56
|
+
Standalone
|
57
|
+
┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┓
|
58
|
+
┃ Name ┃ Type ┃ Features ┃ Scripts ┃
|
59
|
+
┡━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━┩
|
60
|
+
│ default │ virtual │ │ │
|
61
|
+
├─────────┼─────────┼──────────┼─────────┤
|
62
|
+
│ docs │ virtual │ docs │ build │
|
63
|
+
│ │ │ │ serve │
|
64
|
+
└─────────┴─────────┴──────────┴─────────┘
|
65
|
+
Matrices
|
66
|
+
┏━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┓
|
67
|
+
┃ Name ┃ Type ┃ Envs ┃ Features ┃ Scripts ┃
|
68
|
+
┡━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━┩
|
69
|
+
│ dev │ virtual │ dev.jupyterlab-noauth │ test │ lint │
|
70
|
+
│ │ │ dev.jupyterlab-auth │ │ test │
|
71
|
+
│ │ │ dev.jupyterlab-auth_fief │ │ typecheck │
|
72
|
+
│ │ │ dev.retrolab-noauth │ │ │
|
73
|
+
│ │ │ dev.retrolab-auth │ │ │
|
74
|
+
│ │ │ dev.retrolab-auth_fief │ │ │
|
75
|
+
└──────┴─────────┴──────────────────────────┴──────────┴───────────┘
|
76
|
+
```
|
77
|
+
!!! note
|
78
|
+
The `default` environment will install all the plugins from PyPI, **not** from
|
79
|
+
your local repository. The `dev` environment installs all plugins in editable mode
|
80
|
+
from your local repository. So you want to use the `dev` environment.
|
81
|
+
|
82
|
+
Currently, the `dev` environment matrix consists of all combinations of frontends
|
83
|
+
(`jupyterlab`, `retrolab`) and authentication methods (`noauth`, `auth`, `auth_fief`),
|
84
|
+
which leads to six environments.
|
85
|
+
|
86
|
+
A number of scripts are available in the `dev` environments. They can be
|
87
|
+
executed using `hatch run {env}:{script}`. You can also execute anything that you would
|
88
|
+
execute in your shell. For instance, to run Jupyverse for the `jupyterlab` frontend and
|
89
|
+
without authentication, enter:
|
90
|
+
```bash
|
91
|
+
hatch run dev.jupyterlab-noauth:jupyverse
|
92
|
+
```
|
93
|
+
|
94
|
+
Tests should be executed using the `dev.jupyterlab-auth` environment:
|
95
|
+
```bash
|
96
|
+
hatch run dev.jupyterlab-auth:test
|
97
|
+
```
|
98
|
+
Sometimes it is easier to directly be in the environment, without having to prefix everything
|
99
|
+
with `hatch run {env}:`. To do so, just enter:
|
100
|
+
```bash
|
101
|
+
hatch -e dev.jupyterlab-auth shell
|
102
|
+
```
|
103
|
+
You can now directly enter shell commands, e.g. `jupyverse`.
|
104
|
+
To exit the environment, just enter `exit`.
|
105
|
+
|
106
|
+
As the plugins are all installed in editable mode, you could start an instance
|
107
|
+
of Jupyverse in each environment and see how code changes interact with plugins at
|
108
|
+
the same time.
|
109
|
+
|
110
|
+
Finally, `hatch run docs:serve` can be used to view documentation changes.
|
111
|
+
|
112
|
+
If you ever need to start from a fresh environment, you can remove them individually:
|
113
|
+
```bash
|
114
|
+
hatch env remove dev.jupyterlab-auth
|
115
|
+
```
|
116
|
+
Or globally:
|
117
|
+
```bash
|
118
|
+
hatch env prune
|
119
|
+
```
|
@@ -1,24 +1,12 @@
|
|
1
|
-
The auth plugin has a special place because every other plugin depends on it for security reasons.
|
1
|
+
The auth plugin has a special place because almost every other plugin depends on it for security reasons. It is possible to use any auth plugin as long as it follows a defined [API](./#api). Jupyverse comes with three auth plugins: [fps-noauth](./#fps-noauth), [fps-auth](./#fps-auth) and [fps-auth-fief](./#fps-auth-fief).
|
2
2
|
|
3
3
|
## API
|
4
4
|
|
5
|
-
An auth plugin must
|
5
|
+
An auth plugin must implement a class that inherits from the `jupyverse_api.Auth` abstract base class. This class must have the following methods:
|
6
6
|
|
7
|
-
- `
|
7
|
+
- `current_user`: a method that optionally takes in required permissions for the HTTP endpoint, and returns a FastAPI dependency for the currently logged in user after checking that they have permissions. The user must have all the required permissions (if any), otherwise a `403` HTTP code is returned.
|
8
8
|
```py
|
9
|
-
|
10
|
-
username: str = ""
|
11
|
-
name: str = ""
|
12
|
-
display_name: str = ""
|
13
|
-
initials: Optional[str] = None
|
14
|
-
color: Optional[str] = None
|
15
|
-
avatar_url: Optional[str] = None
|
16
|
-
workspace: str = "{}"
|
17
|
-
settings: str = "{}"
|
18
|
-
```
|
19
|
-
- `current_user`: a callable that optionally takes in required permissions for the HTTP endpoint, and returns a FastAPI dependency for the currently logged in user after checking that they have permissions. The user must have all the required permissions (if any), otherwise a `403` HTTP code is returned.
|
20
|
-
```py
|
21
|
-
def current_user(permissions: Optional[Dict[str, List[str]]] = None):
|
9
|
+
def current_user(self, permissions: Optional[Dict[str, List[str]]] = None) -> Callable:
|
22
10
|
async def _current_user():
|
23
11
|
if user_has_permissions(permissions):
|
24
12
|
return User(**{"username": "John"})
|
@@ -26,9 +14,9 @@ def current_user(permissions: Optional[Dict[str, List[str]]] = None):
|
|
26
14
|
|
27
15
|
return _current_user
|
28
16
|
```
|
29
|
-
- `websocket_auth`: a
|
17
|
+
- `websocket_auth`: a method that optionally takes in required permissions for the WebSocket endpoint, and returns a FastAPI dependency for a tuple consisting of the WebSocket object and the checked permissions, if the WebSocket is accepted, or `None` if the WebSocket is refused. If the WebSocket is refused, the dependency has to close the connection, otherwise it has to be accepted by the caller. The user must have at least one of the required permissions (if any) for the WebSocket to be accepted.
|
30
18
|
```py
|
31
|
-
def websocket_auth(permissions: Optional[Dict[str, List[str]]] = None):
|
19
|
+
def websocket_auth(self, permissions: Optional[Dict[str, List[str]]] = None) -> Callable[[], Optional[Tuple[Any, Dict[str, List[str]]]]]:
|
32
20
|
async def _websocket_auth(websocket: WebSocket) -> Optional[Tuple[WebSocket, Optional[Dict[str, List[str]]]]]:
|
33
21
|
accept_websocket = False
|
34
22
|
checked_permissions: Optional[Dict[str, List[str]]] = None
|
@@ -54,7 +42,7 @@ def websocket_auth(permissions: Optional[Dict[str, List[str]]] = None):
|
|
54
42
|
```
|
55
43
|
- `update_user`: a FastAPI dependency for a coroutine that takes in user data to update.
|
56
44
|
```py
|
57
|
-
async def update_user():
|
45
|
+
async def update_user(self) -> Callable:
|
58
46
|
async def _update_user(data: Dict[str, Any]):
|
59
47
|
await update_user_profile(data)
|
60
48
|
|
@@ -67,6 +55,7 @@ async def update_user():
|
|
67
55
|
|
68
56
|
!!! note
|
69
57
|
This can be a security risk! Use it only if you want all endpoints to be accessible by any user.
|
58
|
+
Typically, only do that on your personal computer.
|
70
59
|
|
71
60
|
## fps-auth
|
72
61
|
|
@@ -4,7 +4,7 @@ Jupyverse supports multiple users working collaboratively. Depending on the chos
|
|
4
4
|
|
5
5
|
The first thing to do is to allow collaborative editing when launching Jupyverse:
|
6
6
|
```bash
|
7
|
-
jupyverse --
|
7
|
+
jupyverse --set frontend.collaborative=true
|
8
8
|
```
|
9
9
|
The collaborative mode will handle users through the [auth plugin](../../plugins/auth) you have installed, which will provide user identity.
|
10
10
|
|
@@ -18,7 +18,7 @@ The real power of collaborative editing comes with proper user authentication an
|
|
18
18
|
|
19
19
|
It can be enabled by launching:
|
20
20
|
```bash
|
21
|
-
jupyverse --
|
21
|
+
jupyverse --set frontend.collaborative=true --set auth.mode=token
|
22
22
|
```
|
23
23
|
This uses the token authentication, the same as described in the [single user mode](../single_user/#token-authentication). This means that users don't get a "real" identity, since all they provide is the shared token. For this reason, we call them "anonymous users".
|
24
24
|
|
@@ -26,14 +26,14 @@ They can still be differenciated, and they will each get assigned a different na
|
|
26
26
|
|
27
27
|
You can also disable token authentication in collaborative mode, just as in [single user mode](../single_user/#no-authentication):
|
28
28
|
```bash
|
29
|
-
jupyverse --
|
29
|
+
jupyverse --set frontend.collaborative=true --set auth.mode=noauth
|
30
30
|
```
|
31
31
|
|
32
32
|
#### User authentication
|
33
33
|
|
34
34
|
It can be enabled by launching:
|
35
35
|
```bash
|
36
|
-
jupyverse --
|
36
|
+
jupyverse --set frontend.collaborative=true --set auth.mode=user
|
37
37
|
```
|
38
38
|
In this mode, users have to be registered in a database before logging in. User information includes a user name and a password, that will be asked at login. It can also include a "real" name, that will be displayed when editing documents, and permissions that will determine if they can see or edit a document, run some code, etc.
|
39
39
|
|
@@ -45,5 +45,5 @@ Fief allows to manage users using a dashboard. It supports permissions and Role-
|
|
45
45
|
|
46
46
|
Just launch in a terminal:
|
47
47
|
```bash
|
48
|
-
jupyverse --
|
48
|
+
jupyverse --set frontend.collaborative=true
|
49
49
|
```
|
@@ -1,4 +1,4 @@
|
|
1
|
-
The single user mode is usually meant to run e.g. JupyterLab as a desktop application. Under the hood, a server and a web
|
1
|
+
The single user mode is usually meant to run e.g. JupyterLab as a desktop application. Under the hood, a server and a web frontend are launched, but it should be transparent to the user, who just interacts with a "web app".
|
2
2
|
|
3
3
|
Even though Jupyverse most often runs on a personal computer in this mode, it is not limited to this use case. For instance, if it runs on a network, it could be accessed by other people. It is thus important to limit access to the server, especially considering that Jupyter users can run potentially harmful code.
|
4
4
|
|
@@ -8,15 +8,15 @@ This is why Jupyverse comes with built-in authentication. Please refer to the [a
|
|
8
8
|
|
9
9
|
This is the default mode when launching Jupyverse, just enter in a terminal:
|
10
10
|
```bash
|
11
|
-
jupyverse
|
12
|
-
# same as: jupyverse --auth.mode=token
|
11
|
+
jupyverse --open-browser
|
12
|
+
# same as: jupyverse --set auth.mode=token --open-browser
|
13
13
|
```
|
14
14
|
This should open a new window in a browser, and load JupyterLab or RetroLab, depending on the front-end you chose to install (see [Install](../../install)).
|
15
15
|
|
16
16
|
If you look at the terminal, you should see among other things:
|
17
17
|
```
|
18
|
-
[
|
19
|
-
[
|
18
|
+
[2023-04-05 16:22:39,137 INFO] To access the server, copy and paste this URL:
|
19
|
+
[2023-04-05 16:22:39,137 INFO] http://127.0.0.1:8000/?token=69ce8ccee10d4388b00b3df0d9849700
|
20
20
|
```
|
21
21
|
This is the URL the browser window was opened with, and you can see that a `token` was passed as a query parameter. When the request is made to the server, the token is checked and a cookie is set in the browser. The user is now authenticated and doesn't need to pass the token again in other requests.
|
22
22
|
|
@@ -28,5 +28,5 @@ If you trust everybody who can access the server, you can launch Jupyverse with
|
|
28
28
|
|
29
29
|
Enter in a terminal:
|
30
30
|
```bash
|
31
|
-
jupyverse --auth.mode=noauth
|
31
|
+
jupyverse --set auth.mode=noauth --open-browser
|
32
32
|
```
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.1.2"
|
@@ -0,0 +1,97 @@
|
|
1
|
+
import pkg_resources
|
2
|
+
from typing import List
|
3
|
+
|
4
|
+
import rich_click as click
|
5
|
+
from asphalt.core.cli import run
|
6
|
+
|
7
|
+
|
8
|
+
@click.command()
|
9
|
+
@click.option(
|
10
|
+
"--open-browser",
|
11
|
+
is_flag=True,
|
12
|
+
show_default=True,
|
13
|
+
default=False,
|
14
|
+
help="Open a browser window.",
|
15
|
+
)
|
16
|
+
@click.option(
|
17
|
+
"--host",
|
18
|
+
type=str,
|
19
|
+
default="127.0.0.1",
|
20
|
+
help="The host URL.",
|
21
|
+
)
|
22
|
+
@click.option(
|
23
|
+
"--port",
|
24
|
+
type=int,
|
25
|
+
default=8000,
|
26
|
+
help="The host port.",
|
27
|
+
)
|
28
|
+
@click.option(
|
29
|
+
"--set",
|
30
|
+
"set_",
|
31
|
+
multiple=True,
|
32
|
+
type=str,
|
33
|
+
help="Set configuration.",
|
34
|
+
)
|
35
|
+
@click.option(
|
36
|
+
"--disable",
|
37
|
+
multiple=True,
|
38
|
+
type=str,
|
39
|
+
help="Disable plugin.",
|
40
|
+
)
|
41
|
+
def main(
|
42
|
+
open_browser: bool,
|
43
|
+
host: str,
|
44
|
+
port: int,
|
45
|
+
set_: List[str],
|
46
|
+
disable: List[str],
|
47
|
+
) -> None:
|
48
|
+
set_ = list(set_)
|
49
|
+
for i, s in enumerate(set_):
|
50
|
+
set_[i] = f"component.components.{s}"
|
51
|
+
set_.append(f"component.open_browser={open_browser}")
|
52
|
+
set_.append(f"component.host={host}")
|
53
|
+
set_.append(f"component.port={port}")
|
54
|
+
config = get_config(disable)
|
55
|
+
run.callback(
|
56
|
+
unsafe=False,
|
57
|
+
loop=None,
|
58
|
+
set_=set_,
|
59
|
+
service=None,
|
60
|
+
configfile=[config],
|
61
|
+
) # type: ignore
|
62
|
+
|
63
|
+
|
64
|
+
def get_config(disable: List[str]) -> str:
|
65
|
+
jupyverse_components = [
|
66
|
+
ep.name
|
67
|
+
for ep in pkg_resources.iter_entry_points(group="jupyverse.components")
|
68
|
+
if ep.name not in disable
|
69
|
+
]
|
70
|
+
|
71
|
+
config = ["component:\n type: jupyverse\n components:\n"]
|
72
|
+
for component in jupyverse_components:
|
73
|
+
config.append(f" {component}:\n type: {component}\n")
|
74
|
+
|
75
|
+
config.append(
|
76
|
+
"""
|
77
|
+
logging:
|
78
|
+
version: 1
|
79
|
+
disable_existing_loggers: false
|
80
|
+
formatters:
|
81
|
+
default:
|
82
|
+
format: '[%(asctime)s %(levelname)s] %(message)s'
|
83
|
+
handlers:
|
84
|
+
console:
|
85
|
+
class: logging.StreamHandler
|
86
|
+
formatter: default
|
87
|
+
root:
|
88
|
+
handlers: [console]
|
89
|
+
level: INFO
|
90
|
+
loggers:
|
91
|
+
webnotifier:
|
92
|
+
level: DEBUG
|
93
|
+
"""
|
94
|
+
)
|
95
|
+
|
96
|
+
config_str = "".join(config)
|
97
|
+
return config_str
|
@@ -0,0 +1,42 @@
|
|
1
|
+
from typing import Dict
|
2
|
+
|
3
|
+
from pydantic import BaseModel, Extra
|
4
|
+
|
5
|
+
from .app import App
|
6
|
+
|
7
|
+
|
8
|
+
__version__ = "0.1.2"
|
9
|
+
|
10
|
+
|
11
|
+
class Singleton(type):
|
12
|
+
_instances: Dict = {}
|
13
|
+
|
14
|
+
def __call__(cls, *args, **kwargs):
|
15
|
+
if cls not in cls._instances:
|
16
|
+
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
17
|
+
return cls._instances[cls]
|
18
|
+
|
19
|
+
|
20
|
+
class Config(BaseModel):
|
21
|
+
class Config:
|
22
|
+
extra = Extra.forbid
|
23
|
+
|
24
|
+
|
25
|
+
class Router:
|
26
|
+
_app: App
|
27
|
+
|
28
|
+
def __init__(
|
29
|
+
self,
|
30
|
+
app: App,
|
31
|
+
) -> None:
|
32
|
+
self._app = app
|
33
|
+
|
34
|
+
@property
|
35
|
+
def _type(self):
|
36
|
+
return self.__class__.__name__
|
37
|
+
|
38
|
+
def include_router(self, router, **kwargs):
|
39
|
+
self._app._include_router(router, self._type, **kwargs)
|
40
|
+
|
41
|
+
def mount(self, path: str, *args, **kwargs) -> None:
|
42
|
+
self._app._mount(path, self._type, *args, **kwargs)
|