1
1
import copy
2
+ from typing import Any , Dict
2
3
from uuid import uuid4
3
4
4
5
import y_py as Y
5
- from ypy_websocket .websocket_server import YDoc
6
6
7
7
from .utils import cast_all
8
8
9
9
10
10
class YBaseDoc :
11
- def __init__ (self , ydoc : YDoc ):
11
+ def __init__ (self , ydoc : Y . YDoc ):
12
12
self ._ydoc = ydoc
13
13
self ._ystate = self ._ydoc .get_map ("state" )
14
14
self ._subscriptions = {}
@@ -23,11 +23,11 @@ def ydoc(self):
23
23
24
24
@property
25
25
def source (self ):
26
- raise RuntimeError ( "Y document source generation not implemented" )
26
+ return self . get ( )
27
27
28
28
@source .setter
29
29
def source (self , value ):
30
- raise RuntimeError ( "Y document source initialization not implemented" )
30
+ return self . set ( value )
31
31
32
32
@property
33
33
def dirty (self ) -> None :
@@ -38,6 +38,12 @@ def dirty(self, value: bool) -> None:
38
38
with self ._ydoc .begin_transaction () as t :
39
39
self ._ystate .set (t , "dirty" , value )
40
40
41
+ def get (self ):
42
+ raise RuntimeError ("Y document get not implemented" )
43
+
44
+ def set (self , value ):
45
+ raise RuntimeError ("Y document set not implemented" )
46
+
41
47
def observe (self , callback ):
42
48
raise RuntimeError ("Y document observe not implemented" )
43
49
@@ -52,12 +58,10 @@ def __init__(self, *args, **kwargs):
52
58
super ().__init__ (* args , ** kwargs )
53
59
self ._ysource = self ._ydoc .get_text ("source" )
54
60
55
- @property
56
- def source (self ):
61
+ def get (self ):
57
62
return str (self ._ysource )
58
63
59
- @source .setter
60
- def source (self , value ):
64
+ def set (self , value ):
61
65
with self ._ydoc .begin_transaction () as t :
62
66
# clear document
63
67
source_len = len (self ._ysource )
@@ -79,18 +83,63 @@ def __init__(self, *args, **kwargs):
79
83
self ._ymeta = self ._ydoc .get_map ("meta" )
80
84
self ._ycells = self ._ydoc .get_array ("cells" )
81
85
82
- @property
83
- def source (self ):
86
+ def get_cell (self , index : int ) -> Dict [str , Any ]:
87
+ meta = self ._ymeta .to_json ()
88
+ cell = self ._ycells [index ].to_json ()
89
+ cast_all (cell , float , int )
90
+ if "id" in cell and meta ["nbformat" ] == 4 and meta ["nbformat_minor" ] <= 4 :
91
+ # strip cell IDs if we have notebook format 4.0-4.4
92
+ del cell ["id" ]
93
+ if cell ["cell_type" ] in ["raw" , "markdown" ] and not cell ["attachments" ]:
94
+ del cell ["attachments" ]
95
+ return cell
96
+
97
+ def append_cell (self , value : Dict [str , Any ], txn = None ) -> None :
98
+ ycell = self .create_ycell (value )
99
+ if txn is None :
100
+ with self ._ydoc .begin_transaction () as txn :
101
+ self ._ycells .append (txn , ycell )
102
+ else :
103
+ self ._ycells .append (txn , ycell )
104
+
105
+ def set_cell (self , index : int , value : Dict [str , Any ], txn = None ) -> None :
106
+ ycell = self .create_ycell (value )
107
+ self .set_ycell (index , ycell , txn )
108
+
109
+ def create_ycell (self , value : Dict [str , Any ]) -> None :
110
+ cell = copy .deepcopy (value )
111
+ if "id" not in cell :
112
+ cell ["id" ] = str (uuid4 ())
113
+ cell_type = cell ["cell_type" ]
114
+ cell ["source" ] = Y .YText (cell ["source" ])
115
+ cell ["metadata" ] = Y .YMap (cell .get ("metadata" , {}))
116
+ if cell_type in ("raw" , "markdown" ):
117
+ cell ["attachments" ] = Y .YMap (cell .get ("attachments" , {}))
118
+ elif cell_type == "code" :
119
+ cell ["outputs" ] = Y .YArray (cell .get ("outputs" , []))
120
+ return Y .YMap (cell )
121
+
122
+ def set_ycell (self , index : int , ycell : Y .YMap , txn = None ):
123
+ if txn is None :
124
+ with self ._ydoc .begin_transaction () as txn :
125
+ self ._ycells .delete (txn , index )
126
+ self ._ycells .insert (txn , index , ycell )
127
+ else :
128
+ self ._ycells .delete (txn , index )
129
+ self ._ycells .insert (txn , index , ycell )
130
+
131
+ def get (self ):
84
132
meta = self ._ymeta .to_json ()
85
- cells = self ._ycells .to_json ()
86
133
cast_all (meta , float , int )
87
- cast_all (cells , float , int )
88
- for cell in cells :
134
+ cells = []
135
+ for i in range (len (self ._ycells )):
136
+ cell = self .get_cell (i )
89
137
if "id" in cell and meta ["nbformat" ] == 4 and meta ["nbformat_minor" ] <= 4 :
90
138
# strip cell IDs if we have notebook format 4.0-4.4
91
139
del cell ["id" ]
92
140
if cell ["cell_type" ] in ["raw" , "markdown" ] and not cell ["attachments" ]:
93
141
del cell ["attachments" ]
142
+ cells .append (cell )
94
143
95
144
return dict (
96
145
cells = cells ,
@@ -99,24 +148,22 @@ def source(self):
99
148
nbformat_minor = int (meta ["nbformat_minor" ]),
100
149
)
101
150
102
- @ source . setter
103
- def source ( self , value ):
104
- nb = copy .deepcopy (value )
151
+ def set ( self , value ):
152
+ nb_without_cells = { key : value [ key ] for key in value . keys () if key != "cells" }
153
+ nb = copy .deepcopy (nb_without_cells )
105
154
cast_all (nb , int , float )
106
- if not nb ["cells" ]:
107
- nb ["cells" ] = [
108
- {
109
- "cell_type" : "code" ,
110
- "execution_count" : None ,
111
- "metadata" : {},
112
- "outputs" : [],
113
- "source" : "" ,
114
- "id" : str (uuid4 ()),
115
- }
116
- ]
155
+ cells = value ["cells" ] or [
156
+ {
157
+ "cell_type" : "code" ,
158
+ "execution_count" : None ,
159
+ "metadata" : {},
160
+ "outputs" : [],
161
+ "source" : "" ,
162
+ "id" : str (uuid4 ()),
163
+ }
164
+ ]
117
165
with self ._ydoc .begin_transaction () as t :
118
166
# clear document
119
- # TODO: use clear
120
167
cells_len = len (self ._ycells )
121
168
for key in self ._ymeta :
122
169
self ._ymeta .pop (t , key )
@@ -126,29 +173,7 @@ def source(self, value):
126
173
self ._ystate .pop (t , key )
127
174
128
175
# initialize document
129
- ycells = []
130
- for cell in nb ["cells" ]:
131
- if "id" not in cell :
132
- cell ["id" ] = str (uuid4 ())
133
- cell_type = cell ["cell_type" ]
134
- cell ["source" ] = Y .YText (cell ["source" ])
135
- metadata = {}
136
- if "metadata" in cell :
137
- metadata = cell ["metadata" ]
138
- cell ["metadata" ] = Y .YMap (metadata )
139
- if cell_type in ["raw" , "markdown" ]:
140
- attachments = {}
141
- if "attachments" in cell :
142
- attachments = cell ["attachments" ]
143
- cell ["attachments" ] = Y .YMap (attachments )
144
- elif cell_type == "code" :
145
- outputs = cell .get ("outputs" , [])
146
- cell ["outputs" ] = Y .YArray (outputs )
147
- ycell = Y .YMap (cell )
148
- ycells .append (ycell )
149
-
150
- if ycells :
151
- self ._ycells .extend (t , ycells )
176
+ self ._ycells .extend (t , [self .create_ycell (cell ) for cell in cells ])
152
177
self ._ymeta .set (t , "metadata" , nb ["metadata" ])
153
178
self ._ymeta .set (t , "nbformat" , nb ["nbformat" ])
154
179
self ._ymeta .set (t , "nbformat_minor" , nb ["nbformat_minor" ])
0 commit comments