jupyter-server-ydoc 2.1.0rc0__py3-none-any.whl → 2.1.2__py3-none-any.whl

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.
@@ -1 +1 @@
1
- __version__ = "2.1.0rc0"
1
+ __version__ = "2.1.2"
@@ -10,7 +10,7 @@ from jupyter_server.extension.application import ExtensionApp
10
10
  from jupyter_ydoc import ydocs as YDOCS
11
11
  from jupyter_ydoc.ybasedoc import YBaseDoc
12
12
  from pycrdt import Doc
13
- from pycrdt_websocket.ystore import BaseYStore
13
+ from pycrdt.store import BaseYStore
14
14
  from traitlets import Bool, Float, Type
15
15
 
16
16
  from .handlers import (
@@ -15,9 +15,9 @@ from jupyter_server.auth import authorized
15
15
  from jupyter_server.base.handlers import APIHandler, JupyterHandler
16
16
  from jupyter_server.utils import ensure_async
17
17
  from jupyter_ydoc import ydocs as YDOCS
18
- from pycrdt import Doc, UndoManager
19
- from pycrdt_websocket.yroom import YRoom
20
- from pycrdt_websocket.ystore import BaseYStore
18
+ from pycrdt import Doc, Encoder, UndoManager
19
+ from pycrdt.store import BaseYStore
20
+ from pycrdt.websocket import YRoom
21
21
  from tornado import web
22
22
  from tornado.websocket import WebSocketHandler
23
23
 
@@ -120,7 +120,7 @@ class YDocWebSocketHandler(WebSocketHandler, JupyterHandler):
120
120
  updates_file_path = f".{file_type}:{file_id}.y"
121
121
  ystore = self._ystore_class(
122
122
  path=updates_file_path,
123
- log=self.log, # type:ignore[call-arg]
123
+ log=self.log,
124
124
  )
125
125
  self.room = DocumentRoom(
126
126
  self._room_id,
@@ -273,7 +273,7 @@ class YDocWebSocketHandler(WebSocketHandler, JupyterHandler):
273
273
  if self._room_id != "JupyterLab:globalAwareness":
274
274
  self._emit_awareness_event(self.current_user.username, "join")
275
275
 
276
- async def send(self, message):
276
+ async def send(self, message: bytes) -> None:
277
277
  """
278
278
  Send a message to the client.
279
279
  """
@@ -299,16 +299,38 @@ class YDocWebSocketHandler(WebSocketHandler, JupyterHandler):
299
299
  if header == MessageType.RAW:
300
300
  msg = decoder.read_var_string()
301
301
  if msg == "save":
302
+ save_id = decoder.read_var_uint()
303
+ save_reply = {
304
+ "type": "save",
305
+ "responseTo": save_id,
306
+ }
302
307
  try:
303
308
  room = cast(DocumentRoom, self.room)
304
- room._save_to_disc()
309
+ save_task = room._save_to_disc()
310
+ # task may be missing if save was already in progress
311
+ if save_task:
312
+ await save_task
313
+ await self.send(
314
+ self._encode_json_message({**save_reply, "status": "success"})
315
+ )
316
+ else:
317
+ await self.send(
318
+ self._encode_json_message({**save_reply, "status": "skipped"})
319
+ )
305
320
  except Exception:
306
321
  self.log.error("Couldn't save content from room: %s", self._room_id)
322
+ await self.send(self._encode_json_message({**save_reply, "status": "failed"}))
307
323
  return
308
324
 
309
325
  self._message_queue.put_nowait(message)
310
326
  self._websocket_server.ypatch_nb += 1
311
327
 
328
+ def _encode_json_message(self, message: dict) -> bytes:
329
+ encoder = Encoder()
330
+ encoder.write_var_uint(MessageType.RAW)
331
+ encoder.write_var_string(json.dumps(message))
332
+ return encoder.to_bytes()
333
+
312
334
  def on_close(self) -> None:
313
335
  """
314
336
  On connection close.
@@ -14,13 +14,13 @@ from jupyter_server_ydoc.loaders import FileLoader
14
14
  from jupyter_server_ydoc.rooms import DocumentRoom
15
15
  from jupyter_server_ydoc.stores import SQLiteYStore
16
16
  from jupyter_ydoc import YNotebook, YUnicode
17
- from pycrdt_websocket import WebsocketProvider
17
+ from pycrdt import Provider
18
+ from pycrdt.websocket.websocket import HttpxWebsocket
18
19
 
19
20
  from .test_utils import (
20
21
  FakeContentsManager,
21
22
  FakeEventLogger,
22
23
  FakeFileIDManager,
23
- Websocket,
24
24
  )
25
25
 
26
26
 
@@ -231,7 +231,7 @@ def rtc_add_doc_to_store(rtc_connect_doc_client):
231
231
  doc.observe(_on_document_change)
232
232
 
233
233
  websocket, room_name = await rtc_connect_doc_client(format, type, path)
234
- async with websocket as ws, WebsocketProvider(doc.ydoc, Websocket(ws, room_name)):
234
+ async with websocket as ws, Provider(doc.ydoc, HttpxWebsocket(ws, room_name)):
235
235
  await event.wait()
236
236
  await sleep(0.1)
237
237
 
@@ -243,7 +243,7 @@ def rtc_create_SQLite_store_factory(jp_serverapp):
243
243
  db = SQLiteYStore(
244
244
  path=f"{type}:{path}",
245
245
  # `SQLiteYStore` here is a subclass of booth `LoggingConfigurable`
246
- # and `pycrdt_websocket.ystore.SQLiteYStore`, but mypy gets lost:
246
+ # and `pycrdt.store.SQLiteYStore`, but mypy gets lost:
247
247
  config=jp_serverapp.config, # type:ignore[call-arg]
248
248
  )
249
249
  _ = create_task(db.start())
@@ -9,8 +9,8 @@ from typing import Any, Callable
9
9
 
10
10
  from jupyter_events import EventLogger
11
11
  from jupyter_ydoc import ydocs as YDOCS
12
- from pycrdt_websocket.yroom import YRoom
13
- from pycrdt_websocket.ystore import BaseYStore, YDocNotFound
12
+ from pycrdt.websocket import YRoom
13
+ from pycrdt.store import BaseYStore, YDocNotFound
14
14
 
15
15
  from .loaders import FileLoader
16
16
  from .utils import JUPYTER_COLLABORATION_EVENTS_URI, LogLevel, OutOfBandChanges
@@ -280,6 +280,7 @@ class DocumentRoom(YRoom):
280
280
  self._saving_document = asyncio.create_task(
281
281
  self._maybe_save_document(self._saving_document)
282
282
  )
283
+ return self._saving_document
283
284
 
284
285
  async def _maybe_save_document(self, saving_document: asyncio.Task | None) -> None:
285
286
  """
@@ -1,8 +1,8 @@
1
1
  # Copyright (c) Jupyter Development Team.
2
2
  # Distributed under the terms of the Modified BSD License.
3
3
 
4
- from pycrdt_websocket.ystore import SQLiteYStore as _SQLiteYStore
5
- from pycrdt_websocket.ystore import TempFileYStore as _TempFileYStore
4
+ from pycrdt.store import SQLiteYStore as _SQLiteYStore
5
+ from pycrdt.store import TempFileYStore as _TempFileYStore
6
6
  from traitlets import Int, Unicode
7
7
  from traitlets.config import LoggingConfigurable
8
8
 
@@ -6,7 +6,6 @@ from __future__ import annotations
6
6
  from datetime import datetime
7
7
  from typing import Any
8
8
 
9
- from anyio import Lock
10
9
  from jupyter_server import _tz as tz
11
10
 
12
11
 
@@ -56,32 +55,3 @@ class FakeContentsManager:
56
55
  class FakeEventLogger:
57
56
  def emit(self, schema_id: str, data: dict) -> None:
58
57
  print(data)
59
-
60
-
61
- class Websocket:
62
- def __init__(self, websocket: Any, path: str):
63
- self._websocket = websocket
64
- self._path = path
65
- self._send_lock = Lock()
66
-
67
- @property
68
- def path(self) -> str:
69
- return self._path
70
-
71
- def __aiter__(self):
72
- return self
73
-
74
- async def __anext__(self) -> bytes:
75
- try:
76
- message = await self.recv()
77
- except Exception:
78
- raise StopAsyncIteration()
79
- return message
80
-
81
- async def send(self, message: bytes) -> None:
82
- async with self._send_lock:
83
- await self._websocket.send_bytes(message)
84
-
85
- async def recv(self) -> bytes:
86
- b = await self._websocket.receive_bytes()
87
- return bytes(b)
@@ -7,10 +7,9 @@ import asyncio
7
7
  from logging import Logger
8
8
  from typing import Any, Callable
9
9
 
10
- from pycrdt_websocket.websocket import Websocket
11
- from pycrdt_websocket.websocket_server import WebsocketServer
12
- from pycrdt_websocket.yroom import YRoom
13
- from pycrdt_websocket.ystore import BaseYStore
10
+ from pycrdt import Channel
11
+ from pycrdt.store import BaseYStore
12
+ from pycrdt.websocket import WebsocketServer, YRoom
14
13
 
15
14
 
16
15
  class RoomNotFound(LookupError):
@@ -133,7 +132,7 @@ class JupyterWebsocketServer(WebsocketServer):
133
132
  await self.start_room(room)
134
133
  return room
135
134
 
136
- async def serve(self, websocket: Websocket) -> None:
135
+ async def serve(self, websocket: Channel) -> None:
137
136
  # start monitoring here as the event loop is not yet available when initializing the object
138
137
  if self.monitor_task is None:
139
138
  self.monitor_task = asyncio.create_task(self._monitor())
@@ -1,7 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jupyter-server-ydoc
3
- Version: 2.1.0rc0
3
+ Version: 2.1.2
4
4
  Summary: jupyter-server extension integrating collaborative shared models.
5
+ Project-URL: Documentation, https://jupyterlab-realtime-collaboration.readthedocs.io/
6
+ Project-URL: Repository, https://github.com/jupyterlab/jupyter-collaboration
7
+ Project-URL: Changelog, https://jupyterlab-realtime-collaboration.readthedocs.io/en/latest/changelog.html
8
+ Project-URL: Source, https://github.com/jupyterlab/jupyter-collaboration/tree/main/projects/jupyter-server-ydoc
9
+ Project-URL: Issues, https://github.com/jupyterlab/jupyter-collaboration/issues/new/choose
5
10
  Author-email: Jupyter Development Team <jupyter@googlegroups.com>
6
11
  License: # Licensing terms
7
12
 
@@ -79,9 +84,9 @@ Requires-Dist: jsonschema>=4.18.0
79
84
  Requires-Dist: jupyter-events>=0.11.0
80
85
  Requires-Dist: jupyter-server-fileid<1,>=0.7.0
81
86
  Requires-Dist: jupyter-server<3.0.0,>=2.15.0
82
- Requires-Dist: jupyter-ydoc!=3.0.0,!=3.0.1,<4.0.0,>=2.1.2
87
+ Requires-Dist: jupyter-ydoc<4.0.0,>=3.0.3
83
88
  Requires-Dist: pycrdt
84
- Requires-Dist: pycrdt-websocket<0.16.0,>=0.15.0
89
+ Requires-Dist: pycrdt-websocket<0.17.0,>=0.16.0
85
90
  Provides-Extra: test
86
91
  Requires-Dist: anyio; extra == 'test'
87
92
  Requires-Dist: coverage; extra == 'test'
@@ -0,0 +1,19 @@
1
+ jupyter_server_ydoc/__init__.py,sha256=B8H7XLhzgrTCQD8304Lx91FYXslwabsnV9OuYu4M4Hw,346
2
+ jupyter_server_ydoc/_version.py,sha256=UiuBcRXPtXxPUBDdp0ZDvWl0U9Db1kMNfT3oAfhxqLg,22
3
+ jupyter_server_ydoc/app.py,sha256=GuHiXa2CYvJYEa7dxh9ml5ejcKdjihxCpsbo_AY033c,8150
4
+ jupyter_server_ydoc/handlers.py,sha256=1ZCdwtrlqY2Q9d_A-HV2RL7-bmzcgKvF4H_6PoYoOpQ,28794
5
+ jupyter_server_ydoc/loaders.py,sha256=XUQqg2EbfQUYlQVjHY183gYKeVZ6x92VHy4EsOQz4fA,11303
6
+ jupyter_server_ydoc/pytest_plugin.py,sha256=wpRsCss-TxgCeo8zqJru-YsKflfCGG-T2dbhcfQtMeY,8746
7
+ jupyter_server_ydoc/rooms.py,sha256=dKronZ09LeXS7B5zLQwT6JMbsat75C22-MTg1tjbIq4,13086
8
+ jupyter_server_ydoc/stores.py,sha256=AeGtSA25r5gNRLFp8NPTfjrZMrCrHuGG-8Bjos7iIP0,982
9
+ jupyter_server_ydoc/test_utils.py,sha256=IFXUPf1efHd4DgC1GT7ZMJMhKryKlB0Lx4vU2-mhz4Q,1540
10
+ jupyter_server_ydoc/utils.py,sha256=_wI4CFOEZK4MSMYCZe2moSbggUTRdGxY4qTzSDEFzdE,2183
11
+ jupyter_server_ydoc/websocketserver.py,sha256=4Pxl4EIVIz5TxzNWlSDF6KNzZVkzy5SsgvwJx0PoGtY,5099
12
+ jupyter_server_ydoc/events/awareness.yaml,sha256=2FrCci5rZIaU4rn8pIPZJkd132YAZdzKjSNSwjOY7Dk,755
13
+ jupyter_server_ydoc/events/fork.yaml,sha256=3OrhQjhVyLjlBJWMiffbnZodL3GzFafLwEmSBFrK33o,1303
14
+ jupyter_server_ydoc/events/session.yaml,sha256=PS0MxowpRwY5QFYm-LJvHUxKHnsictV8_6VEwfhYxcQ,1596
15
+ jupyter_server_ydoc-2.1.2.data/data/etc/jupyter/jupyter_server_config.d/jupyter_collaboration.json,sha256=0thh2hJUxAKkZSmneJMG0U6QJRjdM6zGlwrTedEt-Jk,94
16
+ jupyter_server_ydoc-2.1.2.dist-info/METADATA,sha256=j7GXs4t0yZa4fH8QK6_pMF51viwDBpI8V-ZlFyjS1tw,5571
17
+ jupyter_server_ydoc-2.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
+ jupyter_server_ydoc-2.1.2.dist-info/licenses/LICENSE,sha256=mhO0ZW9EiWOPg0dUgB-lNbJ0CGwRmTdbeAg_se1SOnY,2833
19
+ jupyter_server_ydoc-2.1.2.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- jupyter_server_ydoc/__init__.py,sha256=B8H7XLhzgrTCQD8304Lx91FYXslwabsnV9OuYu4M4Hw,346
2
- jupyter_server_ydoc/_version.py,sha256=0eQekZor0gfNEWcMoR45-LXGhlOBJ6C9ZCfeJYvWYU8,25
3
- jupyter_server_ydoc/app.py,sha256=6Zca0acaEFCKyUbXdmcPmVk1Dgu91Y-DFjYR16WKFlg,8161
4
- jupyter_server_ydoc/handlers.py,sha256=WbQLlExk84GsZ0JNA5cmNCbWucruQi0FhQaKG_ZQGiY,27808
5
- jupyter_server_ydoc/loaders.py,sha256=XUQqg2EbfQUYlQVjHY183gYKeVZ6x92VHy4EsOQz4fA,11303
6
- jupyter_server_ydoc/pytest_plugin.py,sha256=yMVlk7fvHXiM7g6ua0Ophc96cFwC0bmTWVDbbUeu2DE,8741
7
- jupyter_server_ydoc/rooms.py,sha256=isX4vHhhvi5WgHtUJBsj29aXw99qoyrO4UOvCij0VbU,13066
8
- jupyter_server_ydoc/stores.py,sha256=_5J6eNs3R5Tv88PCc-GGuszxQstfvNoBCYABqzBzJXA,1004
9
- jupyter_server_ydoc/test_utils.py,sha256=utUwB5FThc_SCQshhUbLNih9GUa5qBcmMgU6-jx0ZnA,2275
10
- jupyter_server_ydoc/utils.py,sha256=_wI4CFOEZK4MSMYCZe2moSbggUTRdGxY4qTzSDEFzdE,2183
11
- jupyter_server_ydoc/websocketserver.py,sha256=h1yTgJcsCK17_97Ne5x-lbgIFsxylwnltxagcuAlTJY,5185
12
- jupyter_server_ydoc/events/awareness.yaml,sha256=2FrCci5rZIaU4rn8pIPZJkd132YAZdzKjSNSwjOY7Dk,755
13
- jupyter_server_ydoc/events/fork.yaml,sha256=3OrhQjhVyLjlBJWMiffbnZodL3GzFafLwEmSBFrK33o,1303
14
- jupyter_server_ydoc/events/session.yaml,sha256=PS0MxowpRwY5QFYm-LJvHUxKHnsictV8_6VEwfhYxcQ,1596
15
- jupyter_server_ydoc-2.1.0rc0.data/data/etc/jupyter/jupyter_server_config.d/jupyter_collaboration.json,sha256=0thh2hJUxAKkZSmneJMG0U6QJRjdM6zGlwrTedEt-Jk,94
16
- jupyter_server_ydoc-2.1.0rc0.dist-info/METADATA,sha256=QlVHazcA7E1nVUcNmuvjUhjUYu96MrxwHLNhWlX2lZo,5118
17
- jupyter_server_ydoc-2.1.0rc0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
- jupyter_server_ydoc-2.1.0rc0.dist-info/licenses/LICENSE,sha256=mhO0ZW9EiWOPg0dUgB-lNbJ0CGwRmTdbeAg_se1SOnY,2833
19
- jupyter_server_ydoc-2.1.0rc0.dist-info/RECORD,,