Skip to content

Commit d94c263

Browse files
committed
Use pycrdt's typed containers
1 parent a329414 commit d94c263

File tree

10 files changed

+200
-89
lines changed

10 files changed

+200
-89
lines changed

Diff for: .github/workflows/test.yml

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ jobs:
4949
run: |
5050
micromamba install pip nodejs=18
5151
pip install ".[test]"
52+
pip install "pycrdt >=0.12.1"
5253
- name: Build JavaScript assets
5354
working-directory: javascript
5455
run: |

Diff for: jupyter_ydoc/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55

66
from ._version import __version__ as __version__
77
from .yblob import YBlob as YBlob
8+
from .yblob import YBlobDoc as YBlobDoc
89
from .yfile import YFile as YFile
10+
from .yfile import YFileDoc as YFileDoc
911
from .ynotebook import YNotebook as YNotebook
12+
from .ynotebook import YNotebookDoc as YNotebookDoc
1013
from .yunicode import YUnicode as YUnicode
14+
from .yunicode import YUnicodeDoc as YUnicodeDoc
1115

1216
# See compatibility note on `group` keyword in
1317
# https://docs.python.org/3/library/importlib.metadata.html#entry-points

Diff for: jupyter_ydoc/ybasedoc.py

+50-29
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
# Copyright (c) Jupyter Development Team.
22
# Distributed under the terms of the Modified BSD License.
33

4+
from __future__ import annotations
5+
46
from abc import ABC, abstractmethod
5-
from typing import Any, Callable, Dict, Optional
7+
from typing import Any, Callable
8+
9+
from pycrdt import Awareness, Doc, Subscription, TypedDoc, TypedMap, UndoManager
10+
11+
12+
class YState(TypedMap):
13+
dirty: bool
14+
hash: str
15+
path: str
616

7-
from pycrdt import Awareness, Doc, Map, Subscription, UndoManager
17+
18+
class YDoc(TypedDoc):
19+
state: YState
820

921

1022
class YBaseDoc(ABC):
@@ -15,12 +27,12 @@ class YBaseDoc(ABC):
1527
subscribe to changes in the document.
1628
"""
1729

18-
_ydoc: Doc
19-
_ystate: Map
20-
_subscriptions: Dict[Any, Subscription]
30+
_ydoc: YDoc
31+
_ystate: YState
32+
_subscriptions: dict[Any, Subscription]
2133
_undo_manager: UndoManager
2234

23-
def __init__(self, ydoc: Optional[Doc] = None, awareness: Optional[Awareness] = None):
35+
def __init__(self, ydoc: YDoc | Doc | None = None, awareness: Awareness | None = None):
2436
"""
2537
Constructs a YBaseDoc.
2638
@@ -30,15 +42,15 @@ def __init__(self, ydoc: Optional[Doc] = None, awareness: Optional[Awareness] =
3042
between clients.
3143
:type awareness: :class:`pycrdt.Awareness`, optional.
3244
"""
33-
if ydoc is None:
34-
self._ydoc = Doc()
35-
else:
45+
if isinstance(ydoc, YDoc):
3646
self._ydoc = ydoc
47+
else:
48+
self._ydoc = YDoc(ydoc)
3749
self.awareness = awareness
3850

39-
self._ystate = self._ydoc.get("state", type=Map)
51+
self._ydoc.state = self._ystate = YState()
4052
self._subscriptions = {}
41-
self._undo_manager = UndoManager(doc=self._ydoc, capture_timeout_millis=0)
53+
self._undo_manager = UndoManager(doc=self._ydoc._, capture_timeout_millis=0)
4254

4355
@property
4456
@abstractmethod
@@ -60,22 +72,22 @@ def undo_manager(self) -> UndoManager:
6072
"""
6173
return self._undo_manager
6274

63-
def ystate(self) -> Map:
75+
def ystate(self) -> YState:
6476
"""
65-
A :class:`pycrdt.Map` containing the state of the document.
77+
A :class:`YState` containing the state of the document.
6678
6779
:return: The document's state.
68-
:rtype: :class:`pycrdt.Map`
80+
:rtype: :class:`YState`
6981
"""
7082
return self._ystate
7183

7284
@property
73-
def ydoc(self) -> Doc:
85+
def ydoc(self) -> YDoc:
7486
"""
75-
The underlying :class:`pycrdt.Doc` that contains the data.
87+
The :class:`YDoc` that contains the data.
7688
7789
:return: The document's ydoc.
78-
:rtype: :class:`pycrdt.Doc`
90+
:rtype: :class:`YDoc`
7991
"""
8092
return self._ydoc
8193

@@ -100,14 +112,17 @@ def source(self, value: Any):
100112
return self.set(value)
101113

102114
@property
103-
def dirty(self) -> Optional[bool]:
115+
def dirty(self) -> bool | None:
104116
"""
105117
Returns whether the document is dirty.
106118
107119
:return: Whether the document is dirty.
108-
:rtype: Optional[bool]
120+
:rtype: bool | None
109121
"""
110-
return self._ystate.get("dirty")
122+
try:
123+
return self._ystate.dirty
124+
except KeyError:
125+
return None
111126

112127
@dirty.setter
113128
def dirty(self, value: bool) -> None:
@@ -117,17 +132,20 @@ def dirty(self, value: bool) -> None:
117132
:param value: Whether the document is clean or dirty.
118133
:type value: bool
119134
"""
120-
self._ystate["dirty"] = value
135+
self._ystate.dirty = value
121136

122137
@property
123-
def hash(self) -> Optional[str]:
138+
def hash(self) -> str | None:
124139
"""
125140
Returns the document hash as computed by contents manager.
126141
127142
:return: The document hash.
128-
:rtype: Optional[str]
143+
:rtype: str | None
129144
"""
130-
return self._ystate.get("hash")
145+
try:
146+
return self._ystate.hash
147+
except KeyError:
148+
return None
131149

132150
@hash.setter
133151
def hash(self, value: str) -> None:
@@ -137,17 +155,20 @@ def hash(self, value: str) -> None:
137155
:param value: The document hash.
138156
:type value: str
139157
"""
140-
self._ystate["hash"] = value
158+
self._ystate.hash = value
141159

142160
@property
143-
def path(self) -> Optional[str]:
161+
def path(self) -> str | None:
144162
"""
145163
Returns document's path.
146164
147165
:return: Document's path.
148-
:rtype: Optional[str]
166+
:rtype: str | None
149167
"""
150-
return self._ystate.get("path")
168+
try:
169+
return self._ystate.path
170+
except KeyError:
171+
return None
151172

152173
@path.setter
153174
def path(self, value: str) -> None:
@@ -157,7 +178,7 @@ def path(self, value: str) -> None:
157178
:param value: Document's path.
158179
:type value: str
159180
"""
160-
self._ystate["path"] = value
181+
self._ystate.path = value
161182

162183
@abstractmethod
163184
def get(self) -> Any:

Diff for: jupyter_ydoc/yblob.py

+27-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
# Copyright (c) Jupyter Development Team.
22
# Distributed under the terms of the Modified BSD License.
33

4+
from __future__ import annotations
5+
46
from functools import partial
5-
from typing import Any, Callable, Optional
7+
from typing import Any, Callable
8+
9+
from pycrdt import Awareness, Doc, TypedMap
10+
11+
from .ybasedoc import YBaseDoc, YDoc
612

7-
from pycrdt import Awareness, Doc, Map
813

9-
from .ybasedoc import YBaseDoc
14+
class YBlobSource(TypedMap):
15+
bytes: bytes
16+
17+
18+
class YBlobDoc(YDoc):
19+
source: YBlobSource
1020

1121

1222
class YBlob(YBaseDoc):
@@ -24,7 +34,10 @@ class YBlob(YBaseDoc):
2434
}
2535
"""
2636

27-
def __init__(self, ydoc: Optional[Doc] = None, awareness: Optional[Awareness] = None):
37+
_ydoc: YBlobDoc
38+
_ysource: YBlobSource
39+
40+
def __init__(self, ydoc: Doc | None = None, awareness: Awareness | None = None):
2841
"""
2942
Constructs a YBlob.
3043
@@ -34,9 +47,9 @@ def __init__(self, ydoc: Optional[Doc] = None, awareness: Optional[Awareness] =
3447
between clients.
3548
:type awareness: :class:`pycrdt.Awareness`, optional.
3649
"""
37-
super().__init__(ydoc, awareness)
38-
self._ysource = self._ydoc.get("source", type=Map)
39-
self.undo_manager.expand_scope(self._ysource)
50+
super().__init__(YBlobDoc(ydoc), awareness)
51+
self._ydoc.source = self._ysource = YBlobSource()
52+
self.undo_manager.expand_scope(self._ysource._)
4053

4154
@property
4255
def version(self) -> str:
@@ -55,7 +68,10 @@ def get(self) -> bytes:
5568
:return: Document's content.
5669
:rtype: bytes
5770
"""
58-
return self._ysource.get("bytes", b"")
71+
try:
72+
return self._ysource.bytes
73+
except KeyError:
74+
return b""
5975

6076
def set(self, value: bytes) -> None:
6177
"""
@@ -64,7 +80,7 @@ def set(self, value: bytes) -> None:
6480
:param value: The content of the document.
6581
:type value: bytes
6682
"""
67-
self._ysource["bytes"] = value
83+
self._ysource.bytes = value
6884

6985
def observe(self, callback: Callable[[str, Any], None]) -> None:
7086
"""
@@ -74,5 +90,5 @@ def observe(self, callback: Callable[[str, Any], None]) -> None:
7490
:type callback: Callable[[str, Any], None]
7591
"""
7692
self.unobserve()
77-
self._subscriptions[self._ystate] = self._ystate.observe(partial(callback, "state"))
78-
self._subscriptions[self._ysource] = self._ysource.observe(partial(callback, "source"))
93+
self._subscriptions[self._ystate] = self._ystate._.observe(partial(callback, "state"))
94+
self._subscriptions[self._ysource] = self._ysource._.observe(partial(callback, "source"))

Diff for: jupyter_ydoc/yfile.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
# Copyright (c) Jupyter Development Team.
22
# Distributed under the terms of the Modified BSD License.
33

4-
from .yunicode import YUnicode
4+
from .yunicode import YUnicode, YUnicodeDoc
55

6+
# For backwards-compatibility:
67

7-
class YFile(YUnicode): # for backwards-compatibility
8+
9+
class YFile(YUnicode):
10+
pass
11+
12+
13+
class YFileDoc(YUnicodeDoc):
814
pass

0 commit comments

Comments
 (0)