1
1
# Copyright (c) Jupyter Development Team.
2
2
# Distributed under the terms of the Modified BSD License.
3
3
4
+ import base64
4
5
import copy
5
6
from abc import ABC , abstractmethod
6
- from typing import Any , Callable , Dict , Optional
7
+ from functools import partial
8
+ from typing import Any , Callable , Dict , Optional , Union
7
9
from uuid import uuid4
8
10
9
11
import y_py as Y
@@ -24,14 +26,17 @@ class YBaseDoc(ABC):
24
26
subscribe to changes in the document.
25
27
"""
26
28
27
- def __init__ (self , ydoc : Y .YDoc ):
29
+ def __init__ (self , ydoc : Optional [ Y .YDoc ] = None ):
28
30
"""
29
31
Constructs a YBaseDoc.
30
32
31
- :param ydoc: The :class:`y_py.YDoc` that will hold the data of the document.
32
- :type ydoc: :class:`y_py.YDoc`
33
+ :param ydoc: The :class:`y_py.YDoc` that will hold the data of the document, if provided .
34
+ :type ydoc: :class:`y_py.YDoc`, optional.
33
35
"""
34
- self ._ydoc = ydoc
36
+ if ydoc is None :
37
+ self ._ydoc = Y .YDoc ()
38
+ else :
39
+ self ._ydoc = ydoc
35
40
self ._ystate = self ._ydoc .get_map ("state" )
36
41
self ._subscriptions = {}
37
42
@@ -125,7 +130,6 @@ def get(self) -> Any:
125
130
:return: Document's content.
126
131
:rtype: Any
127
132
"""
128
- pass
129
133
130
134
@abstractmethod
131
135
def set (self , value : Any ) -> None :
@@ -135,17 +139,15 @@ def set(self, value: Any) -> None:
135
139
:param value: The content of the document.
136
140
:type value: Any
137
141
"""
138
- pass
139
142
140
143
@abstractmethod
141
- def observe (self , callback : Callable [[Any ], None ]) -> None :
144
+ def observe (self , callback : Callable [[str , Any ], None ]) -> None :
142
145
"""
143
146
Subscribes to document changes.
144
147
145
148
:param callback: Callback that will be called when the document changes.
146
- :type callback: Callable[[Any], None]
149
+ :type callback: Callable[[str, Any], None]
147
150
"""
148
- pass
149
151
150
152
def unobserve (self ) -> None :
151
153
"""
@@ -158,9 +160,9 @@ def unobserve(self) -> None:
158
160
self ._subscriptions = {}
159
161
160
162
161
- class YFile (YBaseDoc ):
163
+ class YUnicode (YBaseDoc ):
162
164
"""
163
- Extends :class:`YBaseDoc`, and represents a plain text document.
165
+ Extends :class:`YBaseDoc`, and represents a plain text document, encoded as UTF-8 .
164
166
165
167
Schema:
166
168
@@ -172,12 +174,12 @@ class YFile(YBaseDoc):
172
174
}
173
175
"""
174
176
175
- def __init__ (self , ydoc : Y .YDoc ):
177
+ def __init__ (self , ydoc : Optional [ Y .YDoc ] = None ):
176
178
"""
177
- Constructs a YFile .
179
+ Constructs a YUnicode .
178
180
179
- :param ydoc: The :class:`y_py.YDoc` that will hold the data of the document.
180
- :type ydoc: :class:`y_py.YDoc`
181
+ :param ydoc: The :class:`y_py.YDoc` that will hold the data of the document, if provided .
182
+ :type ydoc: :class:`y_py.YDoc`, optional.
181
183
"""
182
184
super ().__init__ (ydoc )
183
185
self ._ysource = self ._ydoc .get_text ("source" )
@@ -207,16 +209,81 @@ def set(self, value: str) -> None:
207
209
if value :
208
210
self ._ysource .extend (t , value )
209
211
210
- def observe (self , callback : Callable [[Any ], None ]) -> None :
212
+ def observe (self , callback : Callable [[str , Any ], None ]) -> None :
211
213
"""
212
214
Subscribes to document changes.
213
215
214
216
:param callback: Callback that will be called when the document changes.
215
- :type callback: Callable[[Any], None]
217
+ :type callback: Callable[[str, Any], None]
216
218
"""
217
219
self .unobserve ()
218
- self ._subscriptions [self ._ystate ] = self ._ystate .observe (callback )
219
- self ._subscriptions [self ._ysource ] = self ._ysource .observe (callback )
220
+ self ._subscriptions [self ._ystate ] = self ._ystate .observe (partial (callback , "state" ))
221
+ self ._subscriptions [self ._ysource ] = self ._ysource .observe (partial (callback , "source" ))
222
+
223
+
224
+ class YFile (YUnicode ): # for backwards-compatibility
225
+ pass
226
+
227
+
228
+ class YBlob (YBaseDoc ):
229
+ """
230
+ Extends :class:`YBaseDoc`, and represents a blob document.
231
+ It is currently encoded as base64 because of:
232
+ https://github.com/y-crdt/ypy/issues/108#issuecomment-1377055465
233
+ The Y document can be set from bytes or from str, in which case it is assumed to be encoded as
234
+ base64.
235
+
236
+ Schema:
237
+
238
+ .. code-block:: json
239
+
240
+ {
241
+ "state": YMap,
242
+ "source": YMap
243
+ }
244
+ """
245
+
246
+ def __init__ (self , ydoc : Optional [Y .YDoc ] = None ):
247
+ """
248
+ Constructs a YBlob.
249
+
250
+ :param ydoc: The :class:`y_py.YDoc` that will hold the data of the document, if provided.
251
+ :type ydoc: :class:`y_py.YDoc`, optional.
252
+ """
253
+ super ().__init__ (ydoc )
254
+ self ._ysource = self ._ydoc .get_map ("source" )
255
+
256
+ def get (self ) -> bytes :
257
+ """
258
+ Returns the content of the document.
259
+
260
+ :return: Document's content.
261
+ :rtype: bytes
262
+ """
263
+ return base64 .b64decode (self ._ysource .get ("base64" , "" ).encode ())
264
+
265
+ def set (self , value : Union [bytes , str ]) -> None :
266
+ """
267
+ Sets the content of the document.
268
+
269
+ :param value: The content of the document.
270
+ :type value: Union[bytes, str]
271
+ """
272
+ if isinstance (value , bytes ):
273
+ value = base64 .b64encode (value ).decode ()
274
+ with self ._ydoc .begin_transaction () as t :
275
+ self ._ysource .set (t , "base64" , value )
276
+
277
+ def observe (self , callback : Callable [[str , Any ], None ]) -> None :
278
+ """
279
+ Subscribes to document changes.
280
+
281
+ :param callback: Callback that will be called when the document changes.
282
+ :type callback: Callable[[str, Any], None]
283
+ """
284
+ self .unobserve ()
285
+ self ._subscriptions [self ._ystate ] = self ._ystate .observe (partial (callback , "state" ))
286
+ self ._subscriptions [self ._ysource ] = self ._ysource .observe (partial (callback , "source" ))
220
287
221
288
222
289
class YNotebook (YBaseDoc ):
@@ -248,17 +315,27 @@ class YNotebook(YBaseDoc):
248
315
}
249
316
"""
250
317
251
- def __init__ (self , ydoc : Y .YDoc ):
318
+ def __init__ (self , ydoc : Optional [ Y .YDoc ] = None ):
252
319
"""
253
320
Constructs a YNotebook.
254
321
255
- :param ydoc: The :class:`y_py.YDoc` that will hold the data of the document.
256
- :type ydoc: :class:`y_py.YDoc`
322
+ :param ydoc: The :class:`y_py.YDoc` that will hold the data of the document, if provided .
323
+ :type ydoc: :class:`y_py.YDoc`, optional.
257
324
"""
258
325
super ().__init__ (ydoc )
259
326
self ._ymeta = self ._ydoc .get_map ("meta" )
260
327
self ._ycells = self ._ydoc .get_array ("cells" )
261
328
329
+ @property
330
+ def cell_number (self ) -> int :
331
+ """
332
+ Returns the number of cells in the notebook.
333
+
334
+ :return: The cell number.
335
+ :rtype: int
336
+ """
337
+ return len (self ._ycells )
338
+
262
339
def get_cell (self , index : int ) -> Dict [str , Any ]:
263
340
"""
264
341
Returns a cell.
@@ -438,14 +515,14 @@ def set(self, value: Dict) -> None:
438
515
439
516
self ._ymeta .set (t , "metadata" , Y .YMap (metadata ))
440
517
441
- def observe (self , callback : Callable [[Any ], None ]) -> None :
518
+ def observe (self , callback : Callable [[str , Any ], None ]) -> None :
442
519
"""
443
520
Subscribes to document changes.
444
521
445
522
:param callback: Callback that will be called when the document changes.
446
- :type callback: Callable[[Any], None]
523
+ :type callback: Callable[[str, Any], None]
447
524
"""
448
525
self .unobserve ()
449
- self ._subscriptions [self ._ystate ] = self ._ystate .observe (callback )
450
- self ._subscriptions [self ._ymeta ] = self ._ymeta .observe_deep (callback )
451
- self ._subscriptions [self ._ycells ] = self ._ycells .observe_deep (callback )
526
+ self ._subscriptions [self ._ystate ] = self ._ystate .observe (partial ( callback , "state" ) )
527
+ self ._subscriptions [self ._ymeta ] = self ._ymeta .observe_deep (partial ( callback , "meta" ) )
528
+ self ._subscriptions [self ._ycells ] = self ._ycells .observe_deep (partial ( callback , "cells" ) )
0 commit comments