jupyverse 0.1.3__tar.gz → 0.1.4__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.
Files changed (240) hide show
  1. {jupyverse-0.1.3 → jupyverse-0.1.4}/.github/workflows/main.yml +5 -0
  2. {jupyverse-0.1.3 → jupyverse-0.1.4}/.pre-commit-config.yaml +1 -1
  3. {jupyverse-0.1.3 → jupyverse-0.1.4}/CHANGELOG.md +19 -2
  4. {jupyverse-0.1.3 → jupyverse-0.1.4}/PKG-INFO +2 -6
  5. {jupyverse-0.1.3 → jupyverse-0.1.4}/README.md +1 -1
  6. jupyverse-0.1.4/docs/usage/microservices.md +100 -0
  7. jupyverse-0.1.4/jupyverse/__init__.py +1 -0
  8. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/jupyverse_api/__init__.py +1 -1
  9. jupyverse-0.1.4/jupyverse_api/jupyverse_api/contents/__init__.py +185 -0
  10. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/jupyverse_api/contents/models.py +15 -0
  11. jupyverse-0.1.4/jupyverse_api/jupyverse_api/jupyterlab/__init__.py +90 -0
  12. jupyverse-0.1.4/jupyverse_api/jupyverse_api/kernels/__init__.py +230 -0
  13. jupyverse-0.1.4/jupyverse_api/jupyverse_api/lab/__init__.py +193 -0
  14. jupyverse-0.1.4/jupyverse_api/jupyverse_api/login/__init__.py +23 -0
  15. jupyverse-0.1.4/jupyverse_api/jupyverse_api/nbconvert/__init__.py +43 -0
  16. jupyverse-0.1.4/jupyverse_api/jupyverse_api/resource_usage/__init__.py +37 -0
  17. jupyverse-0.1.4/jupyverse_api/jupyverse_api/retrolab/__init__.py +91 -0
  18. jupyverse-0.1.4/jupyverse_api/jupyverse_api/terminals/__init__.py +86 -0
  19. jupyverse-0.1.4/jupyverse_api/jupyverse_api/yjs/__init__.py +72 -0
  20. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/pyproject.toml +8 -1
  21. {jupyverse-0.1.3 → jupyverse-0.1.4}/mkdocs.yml +1 -0
  22. jupyverse-0.1.4/plugins/auth/fps_auth/__init__.py +1 -0
  23. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth/fps_auth/config.py +1 -0
  24. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth/fps_auth/db.py +5 -1
  25. jupyverse-0.1.4/plugins/auth_fief/fps_auth_fief/__init__.py +1 -0
  26. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth_fief/fps_auth_fief/backend.py +2 -2
  27. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth_fief/fps_auth_fief/routes.py +1 -1
  28. jupyverse-0.1.4/plugins/contents/fps_contents/__init__.py +1 -0
  29. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/contents/fps_contents/routes.py +108 -123
  30. jupyverse-0.1.4/plugins/frontend/fps_frontend/__init__.py +1 -0
  31. jupyverse-0.1.4/plugins/jupyterlab/fps_jupyterlab/__init__.py +1 -0
  32. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/jupyterlab/fps_jupyterlab/routes.py +58 -59
  33. jupyverse-0.1.4/plugins/kernels/fps_kernels/__init__.py +1 -0
  34. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/fps_kernels/main.py +5 -1
  35. jupyverse-0.1.4/plugins/kernels/fps_kernels/routes.py +356 -0
  36. jupyverse-0.1.4/plugins/lab/fps_lab/__init__.py +1 -0
  37. jupyverse-0.1.4/plugins/lab/fps_lab/routes.py +205 -0
  38. jupyverse-0.1.4/plugins/login/fps_login/__init__.py +1 -0
  39. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/routes.py +4 -9
  40. jupyverse-0.1.4/plugins/nbconvert/fps_nbconvert/__init__.py +1 -0
  41. jupyverse-0.1.4/plugins/nbconvert/fps_nbconvert/routes.py +41 -0
  42. jupyverse-0.1.4/plugins/noauth/fps_noauth/__init__.py +1 -0
  43. jupyverse-0.1.4/plugins/resource_usage/fps_resource_usage/__init__.py +1 -0
  44. jupyverse-0.1.4/plugins/resource_usage/fps_resource_usage/routes.py +73 -0
  45. jupyverse-0.1.4/plugins/retrolab/fps_retrolab/__init__.py +1 -0
  46. jupyverse-0.1.4/plugins/retrolab/fps_retrolab/routes.py +199 -0
  47. jupyverse-0.1.4/plugins/terminals/fps_terminals/__init__.py +1 -0
  48. jupyverse-0.1.4/plugins/terminals/fps_terminals/routes.py +60 -0
  49. jupyverse-0.1.4/plugins/yjs/fps_yjs/__init__.py +1 -0
  50. jupyverse-0.1.4/plugins/yjs/fps_yjs/routes.py +355 -0
  51. {jupyverse-0.1.3 → jupyverse-0.1.4}/pyproject.toml +25 -28
  52. {jupyverse-0.1.3 → jupyverse-0.1.4}/tests/conftest.py +2 -0
  53. jupyverse-0.1.3/jupyverse/__init__.py +0 -1
  54. jupyverse-0.1.3/jupyverse_api/jupyverse_api/contents/__init__.py +0 -38
  55. jupyverse-0.1.3/jupyverse_api/jupyverse_api/jupyterlab/__init__.py +0 -9
  56. jupyverse-0.1.3/jupyverse_api/jupyverse_api/kernels/__init__.py +0 -16
  57. jupyverse-0.1.3/jupyverse_api/jupyverse_api/lab/__init__.py +0 -18
  58. jupyverse-0.1.3/jupyverse_api/jupyverse_api/login/__init__.py +0 -5
  59. jupyverse-0.1.3/jupyverse_api/jupyverse_api/nbconvert/__init__.py +0 -5
  60. jupyverse-0.1.3/jupyverse_api/jupyverse_api/resource_usage/__init__.py +0 -13
  61. jupyverse-0.1.3/jupyverse_api/jupyverse_api/retrolab/__init__.py +0 -5
  62. jupyverse-0.1.3/jupyverse_api/jupyverse_api/terminals/__init__.py +0 -16
  63. jupyverse-0.1.3/jupyverse_api/jupyverse_api/yjs/__init__.py +0 -7
  64. jupyverse-0.1.3/plugins/auth/fps_auth/__init__.py +0 -1
  65. jupyverse-0.1.3/plugins/auth_fief/fps_auth_fief/__init__.py +0 -1
  66. jupyverse-0.1.3/plugins/contents/fps_contents/__init__.py +0 -1
  67. jupyverse-0.1.3/plugins/contents/fps_contents/models.py +0 -18
  68. jupyverse-0.1.3/plugins/frontend/fps_frontend/__init__.py +0 -1
  69. jupyverse-0.1.3/plugins/jupyterlab/fps_jupyterlab/__init__.py +0 -1
  70. jupyverse-0.1.3/plugins/kernels/fps_kernels/__init__.py +0 -1
  71. jupyverse-0.1.3/plugins/kernels/fps_kernels/routes.py +0 -364
  72. jupyverse-0.1.3/plugins/lab/fps_lab/__init__.py +0 -1
  73. jupyverse-0.1.3/plugins/lab/fps_lab/routes.py +0 -253
  74. jupyverse-0.1.3/plugins/login/fps_login/__init__.py +0 -1
  75. jupyverse-0.1.3/plugins/nbconvert/fps_nbconvert/__init__.py +0 -1
  76. jupyverse-0.1.3/plugins/nbconvert/fps_nbconvert/routes.py +0 -47
  77. jupyverse-0.1.3/plugins/noauth/fps_noauth/__init__.py +0 -1
  78. jupyverse-0.1.3/plugins/resource_usage/fps_resource_usage/__init__.py +0 -1
  79. jupyverse-0.1.3/plugins/resource_usage/fps_resource_usage/routes.py +0 -74
  80. jupyverse-0.1.3/plugins/retrolab/fps_retrolab/__init__.py +0 -1
  81. jupyverse-0.1.3/plugins/retrolab/fps_retrolab/routes.py +0 -170
  82. jupyverse-0.1.3/plugins/terminals/fps_terminals/__init__.py +0 -1
  83. jupyverse-0.1.3/plugins/terminals/fps_terminals/routes.py +0 -66
  84. jupyverse-0.1.3/plugins/yjs/fps_yjs/__init__.py +0 -1
  85. jupyverse-0.1.3/plugins/yjs/fps_yjs/routes.py +0 -360
  86. {jupyverse-0.1.3 → jupyverse-0.1.4}/.devcontainer/devcontainer.json +0 -0
  87. {jupyverse-0.1.3 → jupyverse-0.1.4}/.devcontainer/requirements.txt +0 -0
  88. {jupyverse-0.1.3 → jupyverse-0.1.4}/.github/workflows/check-release.yml +0 -0
  89. {jupyverse-0.1.3 → jupyverse-0.1.4}/.gitignore +0 -0
  90. {jupyverse-0.1.3 → jupyverse-0.1.4}/CONTRIBUTING.md +0 -0
  91. {jupyverse-0.1.3 → jupyverse-0.1.4}/COPYING.md +0 -0
  92. {jupyverse-0.1.3 → jupyverse-0.1.4}/MANIFEST.in +0 -0
  93. {jupyverse-0.1.3 → jupyverse-0.1.4}/binder/environment.yml +0 -0
  94. {jupyverse-0.1.3 → jupyverse-0.1.4}/binder/jupyter_notebook_config.py +0 -0
  95. {jupyverse-0.1.3 → jupyverse-0.1.4}/binder/postBuild +0 -0
  96. {jupyverse-0.1.3 → jupyverse-0.1.4}/binder/start +0 -0
  97. {jupyverse-0.1.3 → jupyverse-0.1.4}/config.yaml +0 -0
  98. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/index.md +0 -0
  99. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/install.md +0 -0
  100. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/jupyter.svg +0 -0
  101. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/auth.md +0 -0
  102. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/contents.md +0 -0
  103. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/frontend.md +0 -0
  104. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/jupyterlab.md +0 -0
  105. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/kernels.md +0 -0
  106. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/lab.md +0 -0
  107. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/login.md +0 -0
  108. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/nbconvert.md +0 -0
  109. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/resource_usage.md +0 -0
  110. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/retrolab.md +0 -0
  111. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/terminals.md +0 -0
  112. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/plugins/yjs.md +0 -0
  113. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/usage/multi_user.md +0 -0
  114. {jupyverse-0.1.3 → jupyverse-0.1.4}/docs/usage/single_user.md +0 -0
  115. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse/py.typed +0 -0
  116. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/COPYING.md +0 -0
  117. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/README.md +0 -0
  118. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/jupyverse_api/app/__init__.py +0 -0
  119. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/jupyverse_api/auth/__init__.py +0 -0
  120. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/jupyverse_api/auth/models.py +0 -0
  121. {jupyverse-0.1.3/jupyverse → jupyverse-0.1.4/jupyverse_api/jupyverse_api}/cli.py +0 -0
  122. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/jupyverse_api/exceptions.py +0 -0
  123. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/jupyverse_api/frontend/__init__.py +0 -0
  124. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/jupyverse_api/kernels/models.py +0 -0
  125. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/jupyverse_api/main/__init__.py +0 -0
  126. {jupyverse-0.1.3 → jupyverse-0.1.4}/jupyverse_api/jupyverse_api/py.typed +0 -0
  127. {jupyverse-0.1.3/plugins/terminals/fps_terminals → jupyverse-0.1.4/jupyverse_api/jupyverse_api/terminals}/models.py +0 -0
  128. {jupyverse-0.1.3/plugins/yjs/fps_yjs → jupyverse-0.1.4/jupyverse_api/jupyverse_api/yjs}/models.py +0 -0
  129. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth/COPYING.md +0 -0
  130. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth/MANIFEST.in +0 -0
  131. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth/README.md +0 -0
  132. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth/fps_auth/backends.py +0 -0
  133. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth/fps_auth/main.py +0 -0
  134. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth/fps_auth/models.py +0 -0
  135. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth/fps_auth/py.typed +0 -0
  136. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth/fps_auth/routes.py +0 -0
  137. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth/pyproject.toml +0 -0
  138. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth_fief/COPYING.md +0 -0
  139. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth_fief/MANIFEST.in +0 -0
  140. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth_fief/README.md +0 -0
  141. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth_fief/fps_auth_fief/config.py +0 -0
  142. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth_fief/fps_auth_fief/main.py +0 -0
  143. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/auth_fief/pyproject.toml +0 -0
  144. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/contents/COPYING.md +0 -0
  145. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/contents/MANIFEST.in +0 -0
  146. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/contents/README.md +0 -0
  147. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/contents/fps_contents/fileid.py +0 -0
  148. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/contents/fps_contents/main.py +0 -0
  149. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/contents/fps_contents/py.typed +0 -0
  150. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/contents/pyproject.toml +0 -0
  151. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/frontend/COPYING.md +0 -0
  152. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/frontend/MANIFEST.in +0 -0
  153. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/frontend/README.md +0 -0
  154. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/frontend/fps_frontend/main.py +0 -0
  155. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/frontend/fps_frontend/py.typed +0 -0
  156. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/frontend/pyproject.toml +0 -0
  157. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/jupyterlab/COPYING.md +0 -0
  158. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/jupyterlab/MANIFEST.in +0 -0
  159. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/jupyterlab/README.md +0 -0
  160. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/jupyterlab/fps_jupyterlab/index.py +0 -0
  161. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/jupyterlab/fps_jupyterlab/main.py +0 -0
  162. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/jupyterlab/fps_jupyterlab/py.typed +0 -0
  163. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/jupyterlab/pyproject.toml +0 -0
  164. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/COPYING.md +0 -0
  165. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/MANIFEST.in +0 -0
  166. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/README.md +0 -0
  167. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/fps_kernels/kernel_driver/__init__.py +0 -0
  168. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/fps_kernels/kernel_driver/connect.py +0 -0
  169. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/fps_kernels/kernel_driver/driver.py +0 -0
  170. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/fps_kernels/kernel_driver/kernelspec.py +0 -0
  171. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/fps_kernels/kernel_driver/message.py +0 -0
  172. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/fps_kernels/kernel_driver/paths.py +0 -0
  173. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/fps_kernels/kernel_server/__init__.py +0 -0
  174. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/fps_kernels/kernel_server/message.py +0 -0
  175. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/fps_kernels/kernel_server/server.py +0 -0
  176. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/kernels/pyproject.toml +0 -0
  177. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/lab/COPYING.md +0 -0
  178. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/lab/MANIFEST.in +0 -0
  179. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/lab/README.md +0 -0
  180. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/lab/fps_lab/main.py +0 -0
  181. {jupyverse-0.1.3/jupyverse → jupyverse-0.1.4/plugins/lab/fps_lab}/static/favicon.ico +0 -0
  182. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/lab/pyproject.toml +0 -0
  183. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/COPYING.md +0 -0
  184. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/MANIFEST.in +0 -0
  185. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/README.md +0 -0
  186. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/main.py +0 -0
  187. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/static/favicons/favicon-busy-1.ico +0 -0
  188. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/static/favicons/favicon-busy-2.ico +0 -0
  189. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/static/favicons/favicon-busy-3.ico +0 -0
  190. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/static/favicons/favicon-file.ico +0 -0
  191. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/static/favicons/favicon-notebook.ico +0 -0
  192. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/static/favicons/favicon-terminal.ico +0 -0
  193. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/static/favicons/favicon.ico +0 -0
  194. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/static/index.html +0 -0
  195. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/static/logo/github.svg +0 -0
  196. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/static/logo/logo.png +0 -0
  197. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/fps_login/static/style/index.css +0 -0
  198. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/login/pyproject.toml +0 -0
  199. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/nbconvert/COPYING.md +0 -0
  200. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/nbconvert/MANIFEST.in +0 -0
  201. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/nbconvert/README.md +0 -0
  202. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/nbconvert/fps_nbconvert/main.py +0 -0
  203. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/nbconvert/pyproject.toml +0 -0
  204. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/noauth/COPYING.md +0 -0
  205. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/noauth/MANIFEST.in +0 -0
  206. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/noauth/README.md +0 -0
  207. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/noauth/fps_noauth/backends.py +0 -0
  208. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/noauth/fps_noauth/main.py +0 -0
  209. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/noauth/fps_noauth/py.typed +0 -0
  210. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/noauth/pyproject.toml +0 -0
  211. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/resource_usage/COPYING.md +0 -0
  212. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/resource_usage/README.md +0 -0
  213. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/resource_usage/fps_resource_usage/main.py +0 -0
  214. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/resource_usage/pyproject.toml +0 -0
  215. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/retrolab/COPYING.md +0 -0
  216. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/retrolab/MANIFEST.in +0 -0
  217. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/retrolab/README.md +0 -0
  218. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/retrolab/fps_retrolab/main.py +0 -0
  219. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/retrolab/pyproject.toml +0 -0
  220. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/terminals/COPYING.md +0 -0
  221. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/terminals/MANIFEST.in +0 -0
  222. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/terminals/README.md +0 -0
  223. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/terminals/fps_terminals/main.py +0 -0
  224. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/terminals/fps_terminals/server.py +0 -0
  225. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/terminals/fps_terminals/win_server.py +0 -0
  226. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/terminals/pyproject.toml +0 -0
  227. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/yjs/COPYING.md +0 -0
  228. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/yjs/MANIFEST.in +0 -0
  229. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/yjs/README.md +0 -0
  230. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/yjs/fps_yjs/main.py +0 -0
  231. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/yjs/fps_yjs/py.typed +0 -0
  232. {jupyverse-0.1.3 → jupyverse-0.1.4}/plugins/yjs/pyproject.toml +0 -0
  233. {jupyverse-0.1.3 → jupyverse-0.1.4}/pytest.ini +0 -0
  234. {jupyverse-0.1.3 → jupyverse-0.1.4}/tests/data/notebook0.ipynb +0 -0
  235. {jupyverse-0.1.3 → jupyverse-0.1.4}/tests/test_auth.py +0 -0
  236. {jupyverse-0.1.3 → jupyverse-0.1.4}/tests/test_contents.py +0 -0
  237. {jupyverse-0.1.3 → jupyverse-0.1.4}/tests/test_kernels.py +0 -0
  238. {jupyverse-0.1.3 → jupyverse-0.1.4}/tests/test_server.py +0 -0
  239. {jupyverse-0.1.3 → jupyverse-0.1.4}/tests/test_settings.py +0 -0
  240. {jupyverse-0.1.3 → jupyverse-0.1.4}/tests/utils.py +0 -0
@@ -41,7 +41,12 @@ jobs:
41
41
 
42
42
  - name: Check types
43
43
  run: |
44
+ hatch run dev.jupyterlab-noauth:typecheck
45
+ hatch run dev.jupyterlab-noauth:typecheck
44
46
  hatch run dev.jupyterlab-auth:typecheck
47
+ hatch run dev.retrolab-auth_fief:typecheck
48
+ hatch run dev.retrolab-auth:typecheck
49
+ hatch run dev.retrolab-auth_fief:typecheck
45
50
 
46
51
  - name: Run tests
47
52
  run: |
@@ -21,7 +21,7 @@ repos:
21
21
  - id: black
22
22
 
23
23
  - repo: https://github.com/charliermarsh/ruff-pre-commit
24
- rev: v0.0.260
24
+ rev: v0.0.261
25
25
  hooks:
26
26
  - id: ruff
27
27
  args: ["--fix"]
@@ -2,6 +2,25 @@
2
2
 
3
3
  <!-- <START NEW CHANGELOG ENTRY> -->
4
4
 
5
+ ## 0.1.4
6
+
7
+ ([Full Changelog](https://github.com/jupyter-server/jupyverse/compare/v0.1.3...a42f7c4d0e951d620108afb4ca25e57da5bae2a1))
8
+
9
+ ### Merged PRs
10
+
11
+ - Move routes to jupyverse_api [#293](https://github.com/jupyter-server/jupyverse/pull/293) ([@davidbrochart](https://github.com/davidbrochart))
12
+ - Add microservices doc, move CLI to jupyverse_api [#292](https://github.com/jupyter-server/jupyverse/pull/292) ([@davidbrochart](https://github.com/davidbrochart))
13
+ - Don't ignore types for fief_client [#290](https://github.com/jupyter-server/jupyverse/pull/290) ([@davidbrochart](https://github.com/davidbrochart))
14
+ - Update README [#288](https://github.com/jupyter-server/jupyverse/pull/288) ([@davidbrochart](https://github.com/davidbrochart))
15
+
16
+ ### Contributors to this release
17
+
18
+ ([GitHub contributors page for this release](https://github.com/jupyter-server/jupyverse/graphs/contributors?from=2023-04-06&to=2023-04-18&type=c))
19
+
20
+ [@davidbrochart](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyverse+involves%3Adavidbrochart+updated%3A2023-04-06..2023-04-18&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyverse+involves%3Apre-commit-ci+updated%3A2023-04-06..2023-04-18&type=Issues)
21
+
22
+ <!-- <END NEW CHANGELOG ENTRY> -->
23
+
5
24
  ## 0.1.3
6
25
 
7
26
  ([Full Changelog](https://github.com/jupyter-server/jupyverse/compare/v0.1.2...b5faf93e3296d855c7ebeda0c25e9861400ad469))
@@ -16,8 +35,6 @@
16
35
 
17
36
  [@davidbrochart](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyverse+involves%3Adavidbrochart+updated%3A2023-04-06..2023-04-06&type=Issues)
18
37
 
19
- <!-- <END NEW CHANGELOG ENTRY> -->
20
-
21
38
  ## 0.1.2
22
39
 
23
40
  No merged PRs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jupyverse
3
- Version: 0.1.3
3
+ Version: 0.1.4
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>
@@ -8,9 +8,6 @@ License: BSD 3-Clause License
8
8
  License-File: COPYING.md
9
9
  Keywords: fastapi,jupyter,plugins,server
10
10
  Requires-Python: >=3.8
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
11
  Requires-Dist: fps-contents<1,>=0.1.2
15
12
  Requires-Dist: fps-frontend<1,>=0.1.2
16
13
  Requires-Dist: fps-kernels<1,>=0.1.2
@@ -19,7 +16,6 @@ Requires-Dist: fps-nbconvert<1,>=0.1.2
19
16
  Requires-Dist: fps-terminals<1,>=0.1.2
20
17
  Requires-Dist: fps-yjs<1,>=0.1.2
21
18
  Requires-Dist: jupyverse-api<1,>=0.1.2
22
- Requires-Dist: rich-click<2,>=1.6.1
23
19
  Provides-Extra: auth
24
20
  Requires-Dist: fps-auth<1,>=0.1.2; extra == 'auth'
25
21
  Provides-Extra: auth-fief
@@ -51,7 +47,7 @@ Description-Content-Type: text/markdown
51
47
 
52
48
  # jupyverse
53
49
 
54
- A set of [FPS](https://github.com/jupyter-server/fps) plugins implementing a Jupyter server.
50
+ A set of [Asphalt](https://asphalt.readthedocs.io) components implementing a Jupyter server.
55
51
 
56
52
  Try it online:
57
53
  - JupyterLab frontend: [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jupyter-server/jupyverse/HEAD?urlpath=jupyverse-jlab)
@@ -3,7 +3,7 @@
3
3
 
4
4
  # jupyverse
5
5
 
6
- A set of [FPS](https://github.com/jupyter-server/fps) plugins implementing a Jupyter server.
6
+ A set of [Asphalt](https://asphalt.readthedocs.io) components implementing a Jupyter server.
7
7
 
8
8
  Try it online:
9
9
  - JupyterLab frontend: [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jupyter-server/jupyverse/HEAD?urlpath=jupyverse-jlab)
@@ -0,0 +1,100 @@
1
+ Jupyverse's modularity allows to run services quite independently from each other, following a microservice architecture. This can be useful when resources are provided by separate systems, or just to have a clear separation of concerns. For instance, you may want to host the contents on AWS and the kernels on Google Cloud, or on different machines in your private network. One way to achieve this is to use a reverse proxy that will forward client requests to the corresponding Jupyverse server. We will show how to do that using [Nginx](https://en.wikipedia.org/wiki/Nginx) on a single computer with local servers. This can serve as a basis for more complicated architectures involving remote servers.
2
+
3
+ ## Nginx setup
4
+
5
+ Nginx is a web server that can also be used as a reverse proxy. We will use it to forward client requests to separate Jupyverse servers, based on the request URL.
6
+
7
+ First, install Nginx in its own environment:
8
+ ```bash
9
+ micromamba create -n nginx
10
+ micromamba activate nginx
11
+ micromamba install -c conda-forge nginx
12
+ ```
13
+ We will just edit the default configuration file at `~/micromamba/envs/nginx/etc/nginx/sites.d/default-site.conf` with the following:
14
+ ```
15
+ server {
16
+ listen 8000;
17
+ server_name localhost;
18
+
19
+ location / {
20
+ proxy_pass http://localhost:8001;
21
+ }
22
+
23
+ location /api/kernelspecs {
24
+ proxy_pass http://localhost:8002;
25
+ }
26
+ location /api/kernels {
27
+ proxy_pass http://localhost:8002;
28
+ }
29
+ location ~ \/api\/kernels\/.+\/channels {
30
+ proxy_pass http://localhost:8002;
31
+ proxy_set_header Upgrade $http_upgrade;
32
+ proxy_set_header Connection "Upgrade";
33
+ }
34
+ location /api/sessions {
35
+ proxy_pass http://localhost:8002;
36
+ }
37
+ }
38
+ ```
39
+ Our Nginx server will listen at `http://localhost:8000`. This is the URL the client will see, i.e. the one we enter in the browser.
40
+
41
+ Our Jupyverse servers will run on:
42
+
43
+ - `http://localhost:8001` for everything except the kernels API. This means that this server doesn't have the ability to run user code, and thus cannot be used to execute a notebook.
44
+ - `http://localhost:8002` for the kernels API. This server only deals with executing code in a kernel. It cannot serve JupyterLab's UI, for instance.
45
+
46
+ Together, these Jupyverse servers can serve a full JupyterLab API. But because they run on different machines (not exactly in this case, since ports `8001` and `8002` are on the same machine, but let's pretend), we need to make them appear as a unique server. That is the role of the reverse proxy server.
47
+
48
+ !!! note
49
+ WebSocket forwarding requires extra-configuration. Here, we use a `regex` to redirect `/api/kernels/{kernel_id}/channels`, which is the WebSocket endpoint for the kernel protocol. We also set the `Upgrade` and `Connection` headers used to upgrade the connection from HTTP to WebSocket.
50
+
51
+ We can now run our reverse proxy server. Just enter:
52
+ ```bash
53
+ nginx
54
+ ```
55
+
56
+ ## Jupyverse setup
57
+
58
+ ### Server 1: everything but kernels
59
+
60
+ Let's create a new environment in a new terminal:
61
+ ```bash
62
+ micromamba create -n jupyverse1
63
+ micromamba activate jupyverse1
64
+ micromamba install -c conda-forge python
65
+ ```
66
+ Since we don't want to install the fully-fledged Jupyverse server, we will install the required plugins individually:
67
+ ```bash
68
+ pip install fps-auth
69
+ pip install fps-contents
70
+ pip install fps-frontend
71
+ pip install fps-lab
72
+ pip install fps-jupyterlab
73
+ pip install fps-login
74
+ ```
75
+ Now just launch Jupyverse at port `8001`:
76
+ ```bash
77
+ jupyverse --port=8001
78
+ ```
79
+ If you open your browser at `http://127.0.0.1:8000` (the URL of the Nginx reverse proxy), you should see the JupyterLab UI you're used to. But if you look closer, you can see that there is no icon for kernels in the launcher tab. And in the terminal where you launched Jupyverse, you will see a bunch of `404` for requests at e.g. `GET /api/kernels`. This is expected, because we didn't install the kernels plugin. You can still use JupyterLab if you don't want to execute a notebook, for instance. But let's close it for now, and install the kernels plugin in another Jupyverse instance.
80
+
81
+ ### Server 2: the kernels API
82
+
83
+ Let's create a new environment in a new terminal:
84
+ ```bash
85
+ micromamba create -n jupyverse2
86
+ micromamba activate jupyverse2
87
+ micromamba install -c conda-forge python
88
+ ```
89
+ This time, we only want to install the kernels plugin. It also requires an authentication system (for the sake of simplicity we will install `fps-noauth` which gives unrestricted access) and the frontend plugin. Let's not forget to install a kernel, such as `ipykernel`:
90
+ ```bash
91
+ pip install fps-kernels
92
+ pip install fps-noauth
93
+ pip install fps-frontend
94
+ pip install ipykernel
95
+ ```
96
+ Launch Juyverse at port `8002`:
97
+ ```bash
98
+ jupyverse --port=8002
99
+ ```
100
+ Now if you re-open a browser at `http://127.0.0.1:8000`, you should be able to create or open a notebook, and execute it.
@@ -0,0 +1 @@
1
+ __version__ = "0.1.4"
@@ -5,7 +5,7 @@ from pydantic import BaseModel, Extra
5
5
  from .app import App
6
6
 
7
7
 
8
- __version__ = "0.1.3"
8
+ __version__ = "0.1.4"
9
9
 
10
10
 
11
11
  class Singleton(type):
@@ -0,0 +1,185 @@
1
+ import asyncio
2
+ from abc import ABC, abstractmethod
3
+ from pathlib import Path
4
+ from typing import Dict, List, Optional, Union
5
+
6
+ from fastapi import APIRouter, Depends, Request, Response
7
+ from jupyverse_api import Router
8
+
9
+ from .models import Checkpoint, Content, SaveContent
10
+ from ..auth import Auth, User
11
+ from ..app import App
12
+
13
+
14
+ class FileIdManager(ABC):
15
+ stop_watching_files: asyncio.Event
16
+ stopped_watching_files: asyncio.Event
17
+
18
+ @abstractmethod
19
+ async def get_path(self, file_id: str) -> str:
20
+ ...
21
+
22
+ @abstractmethod
23
+ async def get_id(self, file_path: str) -> str:
24
+ ...
25
+
26
+
27
+ class Contents(Router, ABC):
28
+ def __init__(self, app: App, auth: Auth):
29
+ super().__init__(app=app)
30
+
31
+ router = APIRouter()
32
+
33
+ @router.post(
34
+ "/api/contents/{path:path}/checkpoints",
35
+ status_code=201,
36
+ )
37
+ async def create_checkpoint(
38
+ path, user: User = Depends(auth.current_user(permissions={"contents": ["write"]}))
39
+ ) -> Checkpoint:
40
+ return await self.create_checkpoint(path, user)
41
+
42
+ @router.post(
43
+ "/api/contents{path:path}",
44
+ status_code=201,
45
+ )
46
+ async def create_content(
47
+ path: Optional[str],
48
+ request: Request,
49
+ user: User = Depends(auth.current_user(permissions={"contents": ["write"]})),
50
+ ) -> Content:
51
+ return await self.create_content(path, request, user)
52
+
53
+ @router.get("/api/contents")
54
+ async def get_root_content(
55
+ content: int,
56
+ user: User = Depends(auth.current_user(permissions={"contents": ["read"]})),
57
+ ) -> Content:
58
+ return await self.get_root_content(content, user)
59
+
60
+ @router.get("/api/contents/{path:path}/checkpoints")
61
+ async def get_checkpoint(
62
+ path, user: User = Depends(auth.current_user(permissions={"contents": ["read"]}))
63
+ ) -> List[Checkpoint]:
64
+ return await self.get_checkpoint(path, user)
65
+
66
+ @router.get("/api/contents/{path:path}")
67
+ async def get_content(
68
+ path: str,
69
+ content: int = 0,
70
+ user: User = Depends(auth.current_user(permissions={"contents": ["read"]})),
71
+ ) -> Content:
72
+ return await self.get_content(path, content, user)
73
+
74
+ @router.put("/api/contents/{path:path}")
75
+ async def save_content(
76
+ path,
77
+ request: Request,
78
+ response: Response,
79
+ user: User = Depends(auth.current_user(permissions={"contents": ["write"]})),
80
+ ) -> Content:
81
+ return await self.save_content(path, request, response, user)
82
+
83
+ @router.delete(
84
+ "/api/contents/{path:path}",
85
+ status_code=204,
86
+ )
87
+ async def delete_content(
88
+ path,
89
+ user: User = Depends(auth.current_user(permissions={"contents": ["write"]})),
90
+ ):
91
+ return await self.delete_content(path, user)
92
+
93
+ @router.patch("/api/contents/{path:path}")
94
+ async def rename_content(
95
+ path,
96
+ request: Request,
97
+ user: User = Depends(auth.current_user(permissions={"contents": ["write"]})),
98
+ ) -> Content:
99
+ return await self.rename_content(path, request, user)
100
+
101
+ self.include_router(router)
102
+
103
+ @property
104
+ @abstractmethod
105
+ def file_id_manager(self) -> FileIdManager:
106
+ ...
107
+
108
+ @abstractmethod
109
+ async def read_content(
110
+ self, path: Union[str, Path], get_content: bool, as_json: bool = False
111
+ ) -> Content:
112
+ ...
113
+
114
+ @abstractmethod
115
+ async def write_content(self, content: Union[SaveContent, Dict]) -> None:
116
+ ...
117
+
118
+ @abstractmethod
119
+ async def create_checkpoint(
120
+ self,
121
+ path,
122
+ user: User,
123
+ ) -> Checkpoint:
124
+ ...
125
+
126
+ @abstractmethod
127
+ async def create_content(
128
+ self,
129
+ path: Optional[str],
130
+ request: Request,
131
+ user: User,
132
+ ) -> Content:
133
+ ...
134
+
135
+ @abstractmethod
136
+ async def get_root_content(
137
+ self,
138
+ content: int,
139
+ user: User,
140
+ ) -> Content:
141
+ return await self.get_root_content(content, user)
142
+
143
+ @abstractmethod
144
+ async def get_checkpoint(
145
+ self,
146
+ path,
147
+ user: User,
148
+ ) -> List[Checkpoint]:
149
+ ...
150
+
151
+ @abstractmethod
152
+ async def get_content(
153
+ self,
154
+ path: str,
155
+ content: int,
156
+ user: User,
157
+ ) -> Content:
158
+ ...
159
+
160
+ @abstractmethod
161
+ async def save_content(
162
+ self,
163
+ path,
164
+ request: Request,
165
+ response: Response,
166
+ user: User,
167
+ ) -> Content:
168
+ ...
169
+
170
+ @abstractmethod
171
+ async def delete_content(
172
+ self,
173
+ path,
174
+ user: User,
175
+ ):
176
+ ...
177
+
178
+ @abstractmethod
179
+ async def rename_content(
180
+ self,
181
+ path,
182
+ request: Request,
183
+ user: User,
184
+ ) -> Content:
185
+ ...
@@ -3,6 +3,11 @@ from typing import Dict, List, Optional, Union
3
3
  from pydantic import BaseModel
4
4
 
5
5
 
6
+ class Checkpoint(BaseModel):
7
+ id: str
8
+ last_modified: str
9
+
10
+
6
11
  class Content(BaseModel):
7
12
  name: str
8
13
  path: str
@@ -16,8 +21,18 @@ class Content(BaseModel):
16
21
  type: str
17
22
 
18
23
 
24
+ class CreateContent(BaseModel):
25
+ ext: Optional[str]
26
+ path: str
27
+ type: str
28
+
29
+
19
30
  class SaveContent(BaseModel):
20
31
  content: Optional[Union[str, Dict]]
21
32
  format: str
22
33
  path: str
23
34
  type: str
35
+
36
+
37
+ class RenameContent(BaseModel):
38
+ path: str
@@ -0,0 +1,90 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from fastapi import APIRouter, Depends, Request
4
+ from fastapi.responses import HTMLResponse
5
+ from jupyverse_api import Config, Router
6
+
7
+ from ..auth import Auth, User
8
+ from ..app import App
9
+
10
+
11
+ class JupyterLab(Router, ABC):
12
+ def __init__(self, app: App, auth: Auth):
13
+ super().__init__(app)
14
+
15
+ router = APIRouter()
16
+
17
+ @router.get("/lab")
18
+ async def get_lab(
19
+ user: User = Depends(auth.current_user()),
20
+ ):
21
+ return await self.get_lab(user)
22
+
23
+ @router.get("/lab/tree/{path:path}")
24
+ async def load_workspace(
25
+ path,
26
+ ):
27
+ return await self.load_workspace(path)
28
+
29
+ @router.get("/lab/api/workspaces/{name}")
30
+ async def get_workspace_data(user: User = Depends(auth.current_user())):
31
+ return await self.get_workspace_data(user)
32
+
33
+ @router.put(
34
+ "/lab/api/workspaces/{name}",
35
+ status_code=204,
36
+ )
37
+ async def set_workspace(
38
+ request: Request,
39
+ user: User = Depends(auth.current_user()),
40
+ user_update=Depends(auth.update_user),
41
+ ):
42
+ return await self.set_workspace(request, user, user_update)
43
+
44
+ @router.get("/lab/workspaces/{name}", response_class=HTMLResponse)
45
+ async def get_workspace(
46
+ name,
47
+ user: User = Depends(auth.current_user()),
48
+ ):
49
+ return await self.get_workspace(name, user)
50
+
51
+ self.include_router(router)
52
+
53
+ @abstractmethod
54
+ async def get_lab(
55
+ self,
56
+ user: User,
57
+ ):
58
+ ...
59
+
60
+ @abstractmethod
61
+ async def load_workspace(
62
+ self,
63
+ path,
64
+ ):
65
+ ...
66
+
67
+ @abstractmethod
68
+ async def get_workspace_data(self, user: User):
69
+ ...
70
+
71
+ @abstractmethod
72
+ async def set_workspace(
73
+ self,
74
+ request: Request,
75
+ user: User,
76
+ user_update,
77
+ ):
78
+ ...
79
+
80
+ @abstractmethod
81
+ async def get_workspace(
82
+ self,
83
+ name,
84
+ user: User,
85
+ ):
86
+ ...
87
+
88
+
89
+ class JupyterLabConfig(Config):
90
+ dev_mode: bool = False