From a6e90e4a247dde477d581f08b0ce847d30d1ae2b Mon Sep 17 00:00:00 2001 From: Nicolas Brichet <32258950+brichet@users.noreply.github.com> Date: Thu, 10 Oct 2024 09:34:38 +0200 Subject: [PATCH] Backport PR #277: Doc awareness --- jupyter_ydoc/ybasedoc.py | 9 +++++++-- jupyter_ydoc/yblob.py | 9 ++++++--- jupyter_ydoc/ynotebook.py | 9 ++++++--- jupyter_ydoc/yunicode.py | 9 ++++++--- pyproject.toml | 4 ++-- tests/test_ydocs.py | 14 +++++++++++++- 6 files changed, 40 insertions(+), 14 deletions(-) diff --git a/jupyter_ydoc/ybasedoc.py b/jupyter_ydoc/ybasedoc.py index aaebe40..a5996b7 100644 --- a/jupyter_ydoc/ybasedoc.py +++ b/jupyter_ydoc/ybasedoc.py @@ -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): @@ -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) diff --git a/jupyter_ydoc/yblob.py b/jupyter_ydoc/yblob.py index a3e0d9a..b87f19a 100644 --- a/jupyter_ydoc/yblob.py +++ b/jupyter_ydoc/yblob.py @@ -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 @@ -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) diff --git a/jupyter_ydoc/ynotebook.py b/jupyter_ydoc/ynotebook.py index b5f737e..aa4380d 100644 --- a/jupyter_ydoc/ynotebook.py +++ b/jupyter_ydoc/ynotebook.py @@ -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 @@ -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) diff --git a/jupyter_ydoc/yunicode.py b/jupyter_ydoc/yunicode.py index 9a010af..50d790c 100644 --- a/jupyter_ydoc/yunicode.py +++ b/jupyter_ydoc/yunicode.py @@ -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 @@ -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) diff --git a/pyproject.toml b/pyproject.toml index cb0d4dd..c75b5e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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]] @@ -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", diff --git a/tests/test_ydocs.py b/tests/test_ydocs.py index b37b180..8567efd 100644 --- a/tests/test_ydocs.py +++ b/tests/test_ydocs.py @@ -1,7 +1,9 @@ # 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_ynotebook_undo_manager(): @@ -33,3 +35,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