Skip to content

Commit

Permalink
Backport PR jupyter-server#277: Doc awareness
Browse files Browse the repository at this point in the history
  • Loading branch information
brichet committed Oct 10, 2024
1 parent a68a8c5 commit 9058aef
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 14 deletions.
9 changes: 7 additions & 2 deletions jupyter_ydoc/ybasedoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from abc import ABC, abstractmethod
from typing import Any, Callable, Dict, Optional

from pycrdt import Doc, Map, Subscription, UndoManager
from pycrdt import Awareness, Doc, Map, Subscription, UndoManager


class YBaseDoc(ABC):
Expand All @@ -20,17 +20,22 @@ class YBaseDoc(ABC):
_subscriptions: Dict[Any, Subscription]
_undo_manager: UndoManager

def __init__(self, ydoc: Optional[Doc] = None):
def __init__(self, ydoc: Optional[Doc] = None, awareness: Optional[Awareness] = None):
"""
Constructs a YBaseDoc.
:param ydoc: The :class:`pycrdt.Doc` that will hold the data of the document, if provided.
:type ydoc: :class:`pycrdt.Doc`, optional.
:param awareness: The :class:`pycrdt.Awareness` that shares non persistent data
between clients.
:type awareness: :class:`pycrdt.Awareness`, optional.
"""
if ydoc is None:
self._ydoc = Doc()
else:
self._ydoc = ydoc
self.awareness = awareness

self._ystate = self._ydoc.get("state", type=Map)
self._subscriptions = {}
self._undo_manager = UndoManager(doc=self._ydoc, capture_timeout_millis=0)
Expand Down
9 changes: 6 additions & 3 deletions jupyter_ydoc/yblob.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from functools import partial
from typing import Any, Callable, Optional, Union

from pycrdt import Doc, Map
from pycrdt import Awareness, Doc, Map

from .ybasedoc import YBaseDoc

Expand All @@ -28,14 +28,17 @@ class YBlob(YBaseDoc):
}
"""

def __init__(self, ydoc: Optional[Doc] = None):
def __init__(self, ydoc: Optional[Doc] = None, awareness: Optional[Awareness] = None):
"""
Constructs a YBlob.
:param ydoc: The :class:`pycrdt.Doc` that will hold the data of the document, if provided.
:type ydoc: :class:`pycrdt.Doc`, optional.
:param awareness: The :class:`pycrdt.Awareness` that shares non persistent data
between clients.
:type awareness: :class:`pycrdt.Awareness`, optional.
"""
super().__init__(ydoc)
super().__init__(ydoc, awareness)
self._ysource = self._ydoc.get("source", type=Map)
self.undo_manager.expand_scope(self._ysource)

Expand Down
9 changes: 6 additions & 3 deletions jupyter_ydoc/ynotebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import Any, Callable, Dict, Optional
from uuid import uuid4

from pycrdt import Array, Doc, Map, Text
from pycrdt import Array, Awareness, Doc, Map, Text

from .utils import cast_all
from .ybasedoc import YBaseDoc
Expand Down Expand Up @@ -46,14 +46,17 @@ class YNotebook(YBaseDoc):
}
"""

def __init__(self, ydoc: Optional[Doc] = None):
def __init__(self, ydoc: Optional[Doc] = None, awareness: Optional[Awareness] = None):
"""
Constructs a YNotebook.
:param ydoc: The :class:`pycrdt.Doc` that will hold the data of the document, if provided.
:type ydoc: :class:`pycrdt.Doc`, optional.
:param awareness: The :class:`pycrdt.Awareness` that shares non persistent data
between clients.
:type awareness: :class:`pycrdt.Awareness`, optional.
"""
super().__init__(ydoc)
super().__init__(ydoc, awareness)
self._ymeta = self._ydoc.get("meta", type=Map)
self._ycells = self._ydoc.get("cells", type=Array)
self.undo_manager.expand_scope(self._ycells)
Expand Down
9 changes: 6 additions & 3 deletions jupyter_ydoc/yunicode.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from functools import partial
from typing import Any, Callable, Optional

from pycrdt import Doc, Text
from pycrdt import Awareness, Doc, Text

from .ybasedoc import YBaseDoc

Expand All @@ -23,14 +23,17 @@ class YUnicode(YBaseDoc):
}
"""

def __init__(self, ydoc: Optional[Doc] = None):
def __init__(self, ydoc: Optional[Doc] = None, awareness: Optional[Awareness] = None):
"""
Constructs a YUnicode.
:param ydoc: The :class:`pycrdt.Doc` that will hold the data of the document, if provided.
:type ydoc: :class:`pycrdt.Doc`, optional.
:param awareness: The :class:`pycrdt.Awareness` that shares non persistent data
between clients.
:type awareness: :class:`pycrdt.Awareness`, optional.
"""
super().__init__(ydoc)
super().__init__(ydoc, awareness)
self._ysource = self._ydoc.get("source", type=Text)
self.undo_manager.expand_scope(self._ysource)

Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ requires-python = ">=3.7"
keywords = ["jupyter", "ypy"]
dependencies = [
"importlib_metadata >=3.6; python_version<'3.10'",
"pycrdt >=0.9.0,<0.10.0",
"pycrdt >=0.10.1,<0.11.0",
]

[[project.authors]]
Expand All @@ -31,7 +31,7 @@ test = [
"pytest",
"pytest-asyncio",
"websockets >=10.0",
"pycrdt-websocket >=0.14.1,<0.15.0",
"pycrdt-websocket >=0.15.0,<0.16.0",
]
docs = [
"sphinx",
Expand Down
34 changes: 33 additions & 1 deletion tests/test_ydocs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.

from jupyter_ydoc import YNotebook
from pycrdt import Awareness, Doc

from jupyter_ydoc import YBlob, YNotebook


def test_yblob():
yblob = YBlob()
assert yblob.get() == b""
yblob.set(b"012")
assert yblob.get() == b"012"
changes = []

def callback(topic, event):
print(topic, event)
changes.append((topic, event))

yblob.observe(callback)
yblob.set(b"345")
assert len(changes) == 1
topic, event = changes[0]
assert topic == "source"
assert event.keys["bytes"]["oldValue"] == b"012"
assert event.keys["bytes"]["newValue"] == b"345"


def test_ynotebook_undo_manager():
Expand Down Expand Up @@ -33,3 +55,13 @@ def test_ynotebook_undo_manager():
ynotebook.undo_manager.undo()
assert len(ynotebook.ycells) == 0
assert not ynotebook.undo_manager.can_undo()


def test_awareness():
yblob = YBlob()
assert yblob.awareness is None

ydoc = Doc()
awareness = Awareness(ydoc)
yblob = YBlob(ydoc, awareness)
assert yblob.awareness == awareness

0 comments on commit 9058aef

Please sign in to comment.