jupyter-server-ydoc-codio 2.1.1__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.
- jupyter_server_ydoc_codio-2.1.1/.gitignore +135 -0
- jupyter_server_ydoc_codio-2.1.1/LICENSE +59 -0
- jupyter_server_ydoc_codio-2.1.1/PKG-INFO +108 -0
- jupyter_server_ydoc_codio-2.1.1/README.md +7 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter-config/jupyter_server_ydoc_codio.json +7 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/__init__.py +11 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/_version.py +1 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/app.py +225 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/custom_stores.py +20 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/events/awareness.yaml +33 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/events/fork.yaml +56 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/events/session.yaml +60 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/handlers.py +726 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/loaders.py +333 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/pytest_plugin.py +312 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/rooms.py +381 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/stores.py +32 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/test_utils.py +57 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/utils.py +80 -0
- jupyter_server_ydoc_codio-2.1.1/jupyter_server_ydoc_codio/websocketserver.py +158 -0
- jupyter_server_ydoc_codio-2.1.1/pyproject.toml +74 -0
- jupyter_server_ydoc_codio-2.1.1/setup.py +5 -0
- jupyter_server_ydoc_codio-2.1.1/tests/__init__.py +2 -0
- jupyter_server_ydoc_codio-2.1.1/tests/conftest.py +8 -0
- jupyter_server_ydoc_codio-2.1.1/tests/test_app.py +123 -0
- jupyter_server_ydoc_codio-2.1.1/tests/test_documents.py +100 -0
- jupyter_server_ydoc_codio-2.1.1/tests/test_handlers.py +358 -0
- jupyter_server_ydoc_codio-2.1.1/tests/test_loaders.py +108 -0
- jupyter_server_ydoc_codio-2.1.1/tests/test_rooms.py +142 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
*.bundle.*
|
|
2
|
+
lib/
|
|
3
|
+
node_modules/
|
|
4
|
+
*.log
|
|
5
|
+
.eslintcache
|
|
6
|
+
.stylelintcache
|
|
7
|
+
*.egg-info/
|
|
8
|
+
.ipynb_checkpoints
|
|
9
|
+
*.tsbuildinfo
|
|
10
|
+
package-lock.json
|
|
11
|
+
docs/source/ts
|
|
12
|
+
.jupyter
|
|
13
|
+
labextension
|
|
14
|
+
|
|
15
|
+
# Integration tests
|
|
16
|
+
ui-tests/test-results/
|
|
17
|
+
ui-tests/playwright-report/
|
|
18
|
+
|
|
19
|
+
# Created by https://www.gitignore.io/api/python
|
|
20
|
+
# Edit at https://www.gitignore.io/?templates=python
|
|
21
|
+
|
|
22
|
+
### Python ###
|
|
23
|
+
# Byte-compiled / optimized / DLL files
|
|
24
|
+
__pycache__/
|
|
25
|
+
*.py[cod]
|
|
26
|
+
*$py.class
|
|
27
|
+
|
|
28
|
+
# C extensions
|
|
29
|
+
*.so
|
|
30
|
+
|
|
31
|
+
# Distribution / packaging
|
|
32
|
+
.Python
|
|
33
|
+
build/
|
|
34
|
+
develop-eggs/
|
|
35
|
+
dist/
|
|
36
|
+
downloads/
|
|
37
|
+
eggs/
|
|
38
|
+
.eggs/
|
|
39
|
+
lib/
|
|
40
|
+
lib64/
|
|
41
|
+
parts/
|
|
42
|
+
sdist/
|
|
43
|
+
var/
|
|
44
|
+
wheels/
|
|
45
|
+
pip-wheel-metadata/
|
|
46
|
+
share/python-wheels/
|
|
47
|
+
.installed.cfg
|
|
48
|
+
*.egg
|
|
49
|
+
MANIFEST
|
|
50
|
+
|
|
51
|
+
# PyInstaller
|
|
52
|
+
# Usually these files are written by a python script from a template
|
|
53
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
54
|
+
*.manifest
|
|
55
|
+
*.spec
|
|
56
|
+
|
|
57
|
+
# Installer logs
|
|
58
|
+
pip-log.txt
|
|
59
|
+
pip-delete-this-directory.txt
|
|
60
|
+
|
|
61
|
+
# Unit test / coverage reports
|
|
62
|
+
htmlcov/
|
|
63
|
+
.tox/
|
|
64
|
+
.nox/
|
|
65
|
+
.coverage
|
|
66
|
+
.coverage.*
|
|
67
|
+
.cache
|
|
68
|
+
nosetests.xml
|
|
69
|
+
coverage/
|
|
70
|
+
coverage.xml
|
|
71
|
+
*.cover
|
|
72
|
+
.hypothesis/
|
|
73
|
+
.pytest_cache/
|
|
74
|
+
|
|
75
|
+
# Translations
|
|
76
|
+
*.mo
|
|
77
|
+
*.pot
|
|
78
|
+
|
|
79
|
+
# Scrapy stuff:
|
|
80
|
+
.scrapy
|
|
81
|
+
|
|
82
|
+
# Sphinx documentation
|
|
83
|
+
docs/_build/
|
|
84
|
+
|
|
85
|
+
# PyBuilder
|
|
86
|
+
target/
|
|
87
|
+
|
|
88
|
+
# pyenv
|
|
89
|
+
.python-version
|
|
90
|
+
|
|
91
|
+
# celery beat schedule file
|
|
92
|
+
celerybeat-schedule
|
|
93
|
+
|
|
94
|
+
# SageMath parsed files
|
|
95
|
+
*.sage.py
|
|
96
|
+
|
|
97
|
+
# Spyder project settings
|
|
98
|
+
.spyderproject
|
|
99
|
+
.spyproject
|
|
100
|
+
|
|
101
|
+
# Rope project settings
|
|
102
|
+
.ropeproject
|
|
103
|
+
|
|
104
|
+
# Mr Developer
|
|
105
|
+
.mr.developer.cfg
|
|
106
|
+
.project
|
|
107
|
+
.pydevproject
|
|
108
|
+
|
|
109
|
+
# mkdocs documentation
|
|
110
|
+
/site
|
|
111
|
+
|
|
112
|
+
# mypy
|
|
113
|
+
.mypy_cache/
|
|
114
|
+
.dmypy.json
|
|
115
|
+
dmypy.json
|
|
116
|
+
|
|
117
|
+
# Pyre type checker
|
|
118
|
+
.pyre/
|
|
119
|
+
|
|
120
|
+
# End of https://www.gitignore.io/api/python
|
|
121
|
+
|
|
122
|
+
# OSX files
|
|
123
|
+
.DS_Store
|
|
124
|
+
docs/source/changelog.md
|
|
125
|
+
|
|
126
|
+
.pnp.*
|
|
127
|
+
.yarn/
|
|
128
|
+
!.yarn/patches
|
|
129
|
+
!.yarn/plugins
|
|
130
|
+
!.yarn/releases
|
|
131
|
+
!.yarn/sdks
|
|
132
|
+
!.yarn/versions
|
|
133
|
+
packages/docprovider/junit.xml
|
|
134
|
+
packages/docprovider-codio/junit.xml
|
|
135
|
+
.jupyter_ystore.db
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Licensing terms
|
|
2
|
+
|
|
3
|
+
This project is licensed under the terms of the Modified BSD License
|
|
4
|
+
(also known as New or Revised or 3-Clause BSD), as follows:
|
|
5
|
+
|
|
6
|
+
- Copyright (c) 2021-, Jupyter Development Team
|
|
7
|
+
|
|
8
|
+
All rights reserved.
|
|
9
|
+
|
|
10
|
+
Redistribution and use in source and binary forms, with or without
|
|
11
|
+
modification, are permitted provided that the following conditions are met:
|
|
12
|
+
|
|
13
|
+
Redistributions of source code must retain the above copyright notice, this
|
|
14
|
+
list of conditions and the following disclaimer.
|
|
15
|
+
|
|
16
|
+
Redistributions in binary form must reproduce the above copyright notice, this
|
|
17
|
+
list of conditions and the following disclaimer in the documentation and/or
|
|
18
|
+
other materials provided with the distribution.
|
|
19
|
+
|
|
20
|
+
Neither the name of the Jupyter Development Team nor the names of its
|
|
21
|
+
contributors may be used to endorse or promote products derived from this
|
|
22
|
+
software without specific prior written permission.
|
|
23
|
+
|
|
24
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
25
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
26
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
27
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
28
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
29
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
30
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
31
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
32
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
33
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
34
|
+
|
|
35
|
+
## About the Jupyter Development Team
|
|
36
|
+
|
|
37
|
+
The Jupyter Development Team is the set of all contributors to the Jupyter project.
|
|
38
|
+
This includes all of the Jupyter subprojects.
|
|
39
|
+
|
|
40
|
+
The core team that coordinates development on GitHub can be found here:
|
|
41
|
+
https://github.com/jupyter/.
|
|
42
|
+
|
|
43
|
+
## Our Copyright Policy
|
|
44
|
+
|
|
45
|
+
Jupyter uses a shared copyright model. Each contributor maintains copyright
|
|
46
|
+
over their contributions to Jupyter. But, it is important to note that these
|
|
47
|
+
contributions are typically only changes to the repositories. Thus, the Jupyter
|
|
48
|
+
source code, in its entirety is not the copyright of any single person or
|
|
49
|
+
institution. Instead, it is the collective copyright of the entire Jupyter
|
|
50
|
+
Development Team. If individual contributors want to maintain a record of what
|
|
51
|
+
changes/contributions they have specific copyright on, they should indicate
|
|
52
|
+
their copyright in the commit message of the change, when they commit the
|
|
53
|
+
change to one of the Jupyter repositories.
|
|
54
|
+
|
|
55
|
+
With this in mind, the following banner should be used in any source code file
|
|
56
|
+
to indicate the copyright and license terms:
|
|
57
|
+
|
|
58
|
+
# Copyright (c) Jupyter Development Team.
|
|
59
|
+
# Distributed under the terms of the Modified BSD License.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jupyter-server-ydoc-codio
|
|
3
|
+
Version: 2.1.1
|
|
4
|
+
Summary: fork of jupyter-server extension integrating collaborative shared models.
|
|
5
|
+
Project-URL: Documentation, https://jupyterlab-realtime-collaboration.readthedocs.io/
|
|
6
|
+
Project-URL: Repository, https://github.com/codio/jupyter-collaboration
|
|
7
|
+
Project-URL: Changelog, https://jupyterlab-realtime-collaboration.readthedocs.io/en/latest/changelog.html
|
|
8
|
+
Project-URL: Source, https://github.com/codio/jupyter-collaboration/tree/main/projects/jupyter-server-ydoc-codio
|
|
9
|
+
Project-URL: Issues, https://github.com/codio/jupyter-collaboration/issues/new/choose
|
|
10
|
+
Author-email: Jupyter Development Team <jupyter@googlegroups.com>
|
|
11
|
+
License: # Licensing terms
|
|
12
|
+
|
|
13
|
+
This project is licensed under the terms of the Modified BSD License
|
|
14
|
+
(also known as New or Revised or 3-Clause BSD), as follows:
|
|
15
|
+
|
|
16
|
+
- Copyright (c) 2021-, Jupyter Development Team
|
|
17
|
+
|
|
18
|
+
All rights reserved.
|
|
19
|
+
|
|
20
|
+
Redistribution and use in source and binary forms, with or without
|
|
21
|
+
modification, are permitted provided that the following conditions are met:
|
|
22
|
+
|
|
23
|
+
Redistributions of source code must retain the above copyright notice, this
|
|
24
|
+
list of conditions and the following disclaimer.
|
|
25
|
+
|
|
26
|
+
Redistributions in binary form must reproduce the above copyright notice, this
|
|
27
|
+
list of conditions and the following disclaimer in the documentation and/or
|
|
28
|
+
other materials provided with the distribution.
|
|
29
|
+
|
|
30
|
+
Neither the name of the Jupyter Development Team nor the names of its
|
|
31
|
+
contributors may be used to endorse or promote products derived from this
|
|
32
|
+
software without specific prior written permission.
|
|
33
|
+
|
|
34
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
35
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
36
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
37
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
38
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
39
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
40
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
41
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
42
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
43
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
44
|
+
|
|
45
|
+
## About the Jupyter Development Team
|
|
46
|
+
|
|
47
|
+
The Jupyter Development Team is the set of all contributors to the Jupyter project.
|
|
48
|
+
This includes all of the Jupyter subprojects.
|
|
49
|
+
|
|
50
|
+
The core team that coordinates development on GitHub can be found here:
|
|
51
|
+
https://github.com/jupyter/.
|
|
52
|
+
|
|
53
|
+
## Our Copyright Policy
|
|
54
|
+
|
|
55
|
+
Jupyter uses a shared copyright model. Each contributor maintains copyright
|
|
56
|
+
over their contributions to Jupyter. But, it is important to note that these
|
|
57
|
+
contributions are typically only changes to the repositories. Thus, the Jupyter
|
|
58
|
+
source code, in its entirety is not the copyright of any single person or
|
|
59
|
+
institution. Instead, it is the collective copyright of the entire Jupyter
|
|
60
|
+
Development Team. If individual contributors want to maintain a record of what
|
|
61
|
+
changes/contributions they have specific copyright on, they should indicate
|
|
62
|
+
their copyright in the commit message of the change, when they commit the
|
|
63
|
+
change to one of the Jupyter repositories.
|
|
64
|
+
|
|
65
|
+
With this in mind, the following banner should be used in any source code file
|
|
66
|
+
to indicate the copyright and license terms:
|
|
67
|
+
|
|
68
|
+
# Copyright (c) Jupyter Development Team.
|
|
69
|
+
# Distributed under the terms of the Modified BSD License.
|
|
70
|
+
License-File: LICENSE
|
|
71
|
+
Classifier: Framework :: Jupyter
|
|
72
|
+
Classifier: Intended Audience :: Developers
|
|
73
|
+
Classifier: Intended Audience :: Science/Research
|
|
74
|
+
Classifier: Intended Audience :: System Administrators
|
|
75
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
76
|
+
Classifier: Programming Language :: Python
|
|
77
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
78
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
79
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
80
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
81
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
82
|
+
Requires-Python: >=3.8
|
|
83
|
+
Requires-Dist: jsonschema>=4.18.0
|
|
84
|
+
Requires-Dist: jupyter-events>=0.11.0
|
|
85
|
+
Requires-Dist: jupyter-server-fileid<1,>=0.7.0
|
|
86
|
+
Requires-Dist: jupyter-server<3.0.0,>=2.15.0
|
|
87
|
+
Requires-Dist: jupyter-ydoc<4.0.0,>=3.0.3
|
|
88
|
+
Requires-Dist: pycrdt
|
|
89
|
+
Requires-Dist: pycrdt-websocket<0.17.0,>=0.16.0
|
|
90
|
+
Provides-Extra: test
|
|
91
|
+
Requires-Dist: anyio; extra == 'test'
|
|
92
|
+
Requires-Dist: coverage; extra == 'test'
|
|
93
|
+
Requires-Dist: dirty-equals; extra == 'test'
|
|
94
|
+
Requires-Dist: httpx-ws>=0.5.2; extra == 'test'
|
|
95
|
+
Requires-Dist: importlib-metadata>=4.8.3; (python_version < '3.10') and extra == 'test'
|
|
96
|
+
Requires-Dist: jupyter-server-fileid[test]; extra == 'test'
|
|
97
|
+
Requires-Dist: jupyter-server[test]>=2.15.0; extra == 'test'
|
|
98
|
+
Requires-Dist: pytest-cov; extra == 'test'
|
|
99
|
+
Requires-Dist: pytest>=7.0; extra == 'test'
|
|
100
|
+
Description-Content-Type: text/markdown
|
|
101
|
+
|
|
102
|
+
# codio fork of jupyter-server-ydoc
|
|
103
|
+
|
|
104
|
+
jupyter-server extension integrating collaborative shared models.
|
|
105
|
+
|
|
106
|
+
The collaborative shared models are used for both:
|
|
107
|
+
- real time collaboration, and
|
|
108
|
+
- server-side execution of notebooks
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Copyright (c) Jupyter Development Team.
|
|
2
|
+
# Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
from typing import Any, Dict, List
|
|
5
|
+
|
|
6
|
+
from ._version import __version__ # noqa
|
|
7
|
+
from .app import YDocExtension
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _jupyter_server_extension_points() -> List[Dict[str, Any]]:
|
|
11
|
+
return [{"module": "jupyter_server_ydoc_codio", "app": YDocExtension}]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.1.1"
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Copyright (c) Jupyter Development Team.
|
|
2
|
+
# Distributed under the terms of the Modified BSD License.
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from functools import partial
|
|
7
|
+
from typing import Literal
|
|
8
|
+
|
|
9
|
+
from jupyter_server.extension.application import ExtensionApp
|
|
10
|
+
from jupyter_ydoc import ydocs as YDOCS
|
|
11
|
+
from jupyter_ydoc.ybasedoc import YBaseDoc
|
|
12
|
+
from pycrdt import Doc
|
|
13
|
+
from pycrdt.store import BaseYStore
|
|
14
|
+
from traitlets import Bool, Float, Type
|
|
15
|
+
|
|
16
|
+
from .handlers import (
|
|
17
|
+
DocForkHandler,
|
|
18
|
+
DocSessionHandler,
|
|
19
|
+
TimelineHandler,
|
|
20
|
+
UndoRedoHandler,
|
|
21
|
+
YDocWebSocketHandler,
|
|
22
|
+
)
|
|
23
|
+
from .loaders import FileLoaderMapping
|
|
24
|
+
from .rooms import DocumentRoom
|
|
25
|
+
from .custom_stores import CustomSQLiteYStore
|
|
26
|
+
from .utils import (
|
|
27
|
+
AWARENESS_EVENTS_SCHEMA_PATH,
|
|
28
|
+
EVENTS_SCHEMA_PATH,
|
|
29
|
+
FORK_EVENTS_SCHEMA_PATH,
|
|
30
|
+
encode_file_path,
|
|
31
|
+
room_id_from_encoded_path,
|
|
32
|
+
)
|
|
33
|
+
from .websocketserver import JupyterWebsocketServer, RoomNotFound, exception_logger
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class YDocExtension(ExtensionApp):
|
|
37
|
+
name = "jupyter_server_ydoc_codio"
|
|
38
|
+
app_name = "Collaboration"
|
|
39
|
+
description = """
|
|
40
|
+
Enables Real Time Collaboration in JupyterLab
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
disable_rtc = Bool(False, config=True, help="Whether to disable real time collaboration.")
|
|
44
|
+
|
|
45
|
+
file_poll_interval = Float(
|
|
46
|
+
1,
|
|
47
|
+
config=True,
|
|
48
|
+
help="""The period in seconds to check for file changes on disk.
|
|
49
|
+
Defaults to 1s, if 0 then file changes will only be checked when
|
|
50
|
+
saving changes from the front-end.""",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
document_cleanup_delay = Float(
|
|
54
|
+
60,
|
|
55
|
+
allow_none=True,
|
|
56
|
+
config=True,
|
|
57
|
+
help="""The delay in seconds to keep a document in memory in the back-end after all clients
|
|
58
|
+
disconnect. Defaults to 60s, if None then the document will be kept in memory forever.""",
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
document_save_delay = Float(
|
|
62
|
+
1,
|
|
63
|
+
allow_none=True,
|
|
64
|
+
config=True,
|
|
65
|
+
help="""The delay in seconds to wait after a change is made to a document before saving it.
|
|
66
|
+
Defaults to 1s, if None then the document will never be saved.""",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
ystore_class = Type(
|
|
70
|
+
default_value=CustomSQLiteYStore,
|
|
71
|
+
klass=BaseYStore,
|
|
72
|
+
config=True,
|
|
73
|
+
help="""The YStore class to use for storing Y updates. Defaults to an SQLiteYStore,
|
|
74
|
+
which stores Y updates in a '.jupyter_ystore.db' SQLite database in the current
|
|
75
|
+
directory.""",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
server_side_execution = Bool(
|
|
79
|
+
False,
|
|
80
|
+
config=True,
|
|
81
|
+
help="""Whether to execute notebooks in the server using the REST API, not using the kernel
|
|
82
|
+
protocol over WebSocket. The frontend only interacts with the notebook through its shared
|
|
83
|
+
model.""",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def initialize(self):
|
|
87
|
+
super().initialize()
|
|
88
|
+
self.serverapp.event_logger.register_event_schema(EVENTS_SCHEMA_PATH)
|
|
89
|
+
self.serverapp.event_logger.register_event_schema(AWARENESS_EVENTS_SCHEMA_PATH)
|
|
90
|
+
self.serverapp.event_logger.register_event_schema(FORK_EVENTS_SCHEMA_PATH)
|
|
91
|
+
|
|
92
|
+
def initialize_settings(self):
|
|
93
|
+
self.settings.update(
|
|
94
|
+
{
|
|
95
|
+
"collaborative_file_poll_interval": self.file_poll_interval,
|
|
96
|
+
"collaborative_document_cleanup_delay": self.document_cleanup_delay,
|
|
97
|
+
"collaborative_document_save_delay": self.document_save_delay,
|
|
98
|
+
"collaborative_ystore_class": self.ystore_class,
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def initialize_handlers(self):
|
|
103
|
+
page_config = self.serverapp.web_app.settings.setdefault("page_config_data", {})
|
|
104
|
+
page_config.setdefault("disableRTC", self.disable_rtc)
|
|
105
|
+
page_config.setdefault("serverSideExecution", self.server_side_execution)
|
|
106
|
+
|
|
107
|
+
# Set configurable parameters to YStore class
|
|
108
|
+
ystore_class: type[BaseYStore] = partial(self.ystore_class, config=self.config) # type:ignore[assignment]
|
|
109
|
+
|
|
110
|
+
self.ywebsocket_server = JupyterWebsocketServer(
|
|
111
|
+
rooms_ready=False,
|
|
112
|
+
auto_clean_rooms=False,
|
|
113
|
+
ystore_class=ystore_class,
|
|
114
|
+
# Log exceptions, because we don't want the websocket server
|
|
115
|
+
# to _ever_ crash permanently in a live jupyter_server.
|
|
116
|
+
exception_handler=exception_logger,
|
|
117
|
+
log=self.log,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# self.settings is local to the ExtensionApp but here we need
|
|
121
|
+
# the global app settings in which the file id manager will register
|
|
122
|
+
# itself maybe at a later time.
|
|
123
|
+
self.file_loaders = FileLoaderMapping(
|
|
124
|
+
self.serverapp.web_app.settings, self.log, self.file_poll_interval
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
self.handlers.extend(
|
|
128
|
+
[
|
|
129
|
+
(
|
|
130
|
+
r"/api/collaboration/fork/(.*)",
|
|
131
|
+
DocForkHandler,
|
|
132
|
+
{
|
|
133
|
+
"ywebsocket_server": self.ywebsocket_server,
|
|
134
|
+
},
|
|
135
|
+
),
|
|
136
|
+
(
|
|
137
|
+
r"/api/collaboration/room/(.*)",
|
|
138
|
+
YDocWebSocketHandler,
|
|
139
|
+
{
|
|
140
|
+
"document_cleanup_delay": self.document_cleanup_delay,
|
|
141
|
+
"document_save_delay": self.document_save_delay,
|
|
142
|
+
"file_loaders": self.file_loaders,
|
|
143
|
+
"ystore_class": ystore_class,
|
|
144
|
+
"ywebsocket_server": self.ywebsocket_server,
|
|
145
|
+
},
|
|
146
|
+
),
|
|
147
|
+
(r"/api/collaboration/session/(.*)", DocSessionHandler),
|
|
148
|
+
(
|
|
149
|
+
r"/api/collaboration/timeline/(.*)",
|
|
150
|
+
TimelineHandler,
|
|
151
|
+
{
|
|
152
|
+
"ystore_class": self.ystore_class,
|
|
153
|
+
"ywebsocket_server": self.ywebsocket_server,
|
|
154
|
+
},
|
|
155
|
+
),
|
|
156
|
+
(
|
|
157
|
+
r"/api/collaboration/undo_redo/(.*)",
|
|
158
|
+
UndoRedoHandler,
|
|
159
|
+
{
|
|
160
|
+
"ywebsocket_server": self.ywebsocket_server,
|
|
161
|
+
},
|
|
162
|
+
),
|
|
163
|
+
]
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
async def get_document(
|
|
167
|
+
self: YDocExtension,
|
|
168
|
+
*,
|
|
169
|
+
path: str | None = None,
|
|
170
|
+
content_type: str | None = None,
|
|
171
|
+
file_format: Literal["json", "text"] | None = None,
|
|
172
|
+
room_id: str | None = None,
|
|
173
|
+
copy: bool = True,
|
|
174
|
+
) -> YBaseDoc | None:
|
|
175
|
+
"""Get a view of the shared model for the matching document.
|
|
176
|
+
|
|
177
|
+
You need to provide either a ``room_id`` or the ``path``,
|
|
178
|
+
the ``content_type`` and the ``file_format``.
|
|
179
|
+
|
|
180
|
+
If `copy=True`, the returned shared model is a fork, meaning that any changes
|
|
181
|
+
made to it will not be propagated to the shared model used by the application.
|
|
182
|
+
"""
|
|
183
|
+
error_msg = "You need to provide either a ``room_id`` or the ``path``, the ``content_type`` and the ``file_format``."
|
|
184
|
+
if room_id is None:
|
|
185
|
+
if path is None or content_type is None or file_format is None:
|
|
186
|
+
raise ValueError(error_msg)
|
|
187
|
+
|
|
188
|
+
file_id_manager = self.serverapp.web_app.settings["file_id_manager"]
|
|
189
|
+
file_id = file_id_manager.index(path)
|
|
190
|
+
|
|
191
|
+
encoded_path = encode_file_path(file_format, content_type, file_id)
|
|
192
|
+
room_id = room_id_from_encoded_path(encoded_path)
|
|
193
|
+
|
|
194
|
+
elif path is not None or content_type is not None or file_format is not None:
|
|
195
|
+
raise ValueError(error_msg)
|
|
196
|
+
else:
|
|
197
|
+
room_id = room_id
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
room = await self.ywebsocket_server.get_room(room_id)
|
|
201
|
+
except RoomNotFound:
|
|
202
|
+
return None
|
|
203
|
+
|
|
204
|
+
if isinstance(room, DocumentRoom):
|
|
205
|
+
if copy:
|
|
206
|
+
update = room.ydoc.get_update()
|
|
207
|
+
|
|
208
|
+
fork_ydoc: Doc = Doc()
|
|
209
|
+
fork_ydoc.apply_update(update)
|
|
210
|
+
|
|
211
|
+
return YDOCS.get(room.file_type, YDOCS["file"])(fork_ydoc)
|
|
212
|
+
else:
|
|
213
|
+
return room._document
|
|
214
|
+
|
|
215
|
+
return None
|
|
216
|
+
|
|
217
|
+
async def stop_extension(self):
|
|
218
|
+
# Cancel tasks and clean up
|
|
219
|
+
await asyncio.wait(
|
|
220
|
+
[
|
|
221
|
+
asyncio.create_task(self.ywebsocket_server.clean()),
|
|
222
|
+
asyncio.create_task(self.file_loaders.clear()),
|
|
223
|
+
],
|
|
224
|
+
timeout=3,
|
|
225
|
+
)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Copyright (c) Jupyter Development Team.
|
|
2
|
+
# Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from traitlets import Unicode
|
|
6
|
+
from .stores import SQLiteYStore
|
|
7
|
+
|
|
8
|
+
class CustomSQLiteYStore(SQLiteYStore):
|
|
9
|
+
db_dir = ".guides"
|
|
10
|
+
|
|
11
|
+
db_path = Unicode(
|
|
12
|
+
".guides/.jupyter_ystore.db",
|
|
13
|
+
config=True,
|
|
14
|
+
help="""The path to the YStore database. Defaults to '.guides/.jupyter_ystore.db' in the current
|
|
15
|
+
directory.""",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def __init__(self, **kwargs):
|
|
19
|
+
Path(self.db_dir).mkdir(parents=True, exist_ok=True)
|
|
20
|
+
super().__init__(**kwargs)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"$id": https://schema.jupyter.org/jupyter_collaboration/awareness/v1
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema"
|
|
3
|
+
version: "1"
|
|
4
|
+
title: Collaborative awareness events
|
|
5
|
+
personal-data: true
|
|
6
|
+
description: |
|
|
7
|
+
Awareness events emitted from server-side during a collaborative session.
|
|
8
|
+
type: object
|
|
9
|
+
required:
|
|
10
|
+
- roomid
|
|
11
|
+
- username
|
|
12
|
+
- action
|
|
13
|
+
properties:
|
|
14
|
+
roomid:
|
|
15
|
+
type: string
|
|
16
|
+
description: |
|
|
17
|
+
Room ID. Usually composed by the file type, format and ID.
|
|
18
|
+
username:
|
|
19
|
+
type: string
|
|
20
|
+
description: |
|
|
21
|
+
The name of the user who joined or left room.
|
|
22
|
+
action:
|
|
23
|
+
enum:
|
|
24
|
+
- join
|
|
25
|
+
- leave
|
|
26
|
+
description: |
|
|
27
|
+
Possible values:
|
|
28
|
+
1. join
|
|
29
|
+
2. leave
|
|
30
|
+
msg:
|
|
31
|
+
type: string
|
|
32
|
+
description: |
|
|
33
|
+
Optional event message.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"$id": https://schema.jupyter.org/jupyter_collaboration/fork/v1
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema"
|
|
3
|
+
version: "1"
|
|
4
|
+
title: Collaborative fork events
|
|
5
|
+
personal-data: true
|
|
6
|
+
description: |
|
|
7
|
+
Fork events emitted from server-side during a collaborative session.
|
|
8
|
+
type: object
|
|
9
|
+
required:
|
|
10
|
+
- fork_roomid
|
|
11
|
+
- fork_info
|
|
12
|
+
- username
|
|
13
|
+
- action
|
|
14
|
+
properties:
|
|
15
|
+
fork_roomid:
|
|
16
|
+
type: string
|
|
17
|
+
description: |
|
|
18
|
+
Fork root room ID.
|
|
19
|
+
fork_info:
|
|
20
|
+
type: object
|
|
21
|
+
description: |
|
|
22
|
+
Fork root room information.
|
|
23
|
+
required:
|
|
24
|
+
- root_roomid
|
|
25
|
+
- synchronize
|
|
26
|
+
- title
|
|
27
|
+
- description
|
|
28
|
+
properties:
|
|
29
|
+
root_roomid:
|
|
30
|
+
type: string
|
|
31
|
+
description: |
|
|
32
|
+
Root room ID. Usually composed by the file type, format and ID.
|
|
33
|
+
synchronize:
|
|
34
|
+
type: boolean
|
|
35
|
+
description: |
|
|
36
|
+
Whether the fork is kept in sync with the root.
|
|
37
|
+
title:
|
|
38
|
+
type: string
|
|
39
|
+
description: |
|
|
40
|
+
The title of the fork.
|
|
41
|
+
description:
|
|
42
|
+
type: string
|
|
43
|
+
description: |
|
|
44
|
+
The description of the fork.
|
|
45
|
+
username:
|
|
46
|
+
type: string
|
|
47
|
+
description: |
|
|
48
|
+
The name of the user who created or deleted the fork.
|
|
49
|
+
action:
|
|
50
|
+
enum:
|
|
51
|
+
- create
|
|
52
|
+
- delete
|
|
53
|
+
description: |
|
|
54
|
+
Possible values:
|
|
55
|
+
1. create
|
|
56
|
+
2. delete
|