Skip to content

Commit

Permalink
Doc awareness (#277)
Browse files Browse the repository at this point in the history
* Add an awareness in the YDoc on server side

* Test awareness getter/setter

* Depend on pycrdt instead of pycrdt_websocket

* Apply suggestions from code review

Co-authored-by: David Brochart <[email protected]>

* Apply suggestions from review

Co-authored-by: David Brochart <[email protected]>

* Apply suggestions from code review

Co-authored-by: David Brochart <[email protected]>

* Apply suggestions from code review

Co-authored-by: David Brochart <[email protected]>

* Update pycrdt_websocket for tests

---------

Co-authored-by: David Brochart <[email protected]>
Co-authored-by: David Brochart <[email protected]>
  • Loading branch information
3 people authored Oct 10, 2024
1 parent bf2db86 commit 877e5b9
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 13 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 @@ -4,7 +4,7 @@
from functools import partial
from typing import Any, Callable, Optional

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

from .ybasedoc import YBaseDoc

Expand All @@ -24,14 +24,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 @@ -47,14 +47,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.8"
keywords = ["jupyter", "pycrdt", "yjs"]
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
12 changes: 12 additions & 0 deletions tests/test_ydocs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.

from pycrdt import Awareness, Doc

from jupyter_ydoc import YBlob, YNotebook


Expand Down Expand Up @@ -53,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 877e5b9

Please sign in to comment.