11import copy
2+ from typing import Any , Dict
23from uuid import uuid4
34
45import y_py as Y
5- from ypy_websocket .websocket_server import YDoc
66
77from .utils import cast_all
88
99
1010class YBaseDoc :
11- def __init__ (self , ydoc : YDoc ):
11+ def __init__ (self , ydoc : Y . YDoc ):
1212 self ._ydoc = ydoc
1313 self ._ystate = self ._ydoc .get_map ("state" )
1414 self ._subscriptions = {}
@@ -23,11 +23,11 @@ def ydoc(self):
2323
2424 @property
2525 def source (self ):
26- raise RuntimeError ( "Y document source generation not implemented" )
26+ return self . get ( )
2727
2828 @source .setter
2929 def source (self , value ):
30- raise RuntimeError ( "Y document source initialization not implemented" )
30+ return self . set ( value )
3131
3232 @property
3333 def dirty (self ) -> None :
@@ -38,6 +38,12 @@ def dirty(self, value: bool) -> None:
3838 with self ._ydoc .begin_transaction () as t :
3939 self ._ystate .set (t , "dirty" , value )
4040
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+
4147 def observe (self , callback ):
4248 raise RuntimeError ("Y document observe not implemented" )
4349
@@ -52,12 +58,10 @@ def __init__(self, *args, **kwargs):
5258 super ().__init__ (* args , ** kwargs )
5359 self ._ysource = self ._ydoc .get_text ("source" )
5460
55- @property
56- def source (self ):
61+ def get (self ):
5762 return str (self ._ysource )
5863
59- @source .setter
60- def source (self , value ):
64+ def set (self , value ):
6165 with self ._ydoc .begin_transaction () as t :
6266 # clear document
6367 source_len = len (self ._ysource )
@@ -79,18 +83,63 @@ def __init__(self, *args, **kwargs):
7983 self ._ymeta = self ._ydoc .get_map ("meta" )
8084 self ._ycells = self ._ydoc .get_array ("cells" )
8185
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 ):
84132 meta = self ._ymeta .to_json ()
85- cells = self ._ycells .to_json ()
86133 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 )
89137 if "id" in cell and meta ["nbformat" ] == 4 and meta ["nbformat_minor" ] <= 4 :
90138 # strip cell IDs if we have notebook format 4.0-4.4
91139 del cell ["id" ]
92140 if cell ["cell_type" ] in ["raw" , "markdown" ] and not cell ["attachments" ]:
93141 del cell ["attachments" ]
142+ cells .append (cell )
94143
95144 return dict (
96145 cells = cells ,
@@ -99,24 +148,22 @@ def source(self):
99148 nbformat_minor = int (meta ["nbformat_minor" ]),
100149 )
101150
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 )
105154 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+ ]
117165 with self ._ydoc .begin_transaction () as t :
118166 # clear document
119- # TODO: use clear
120167 cells_len = len (self ._ycells )
121168 for key in self ._ymeta :
122169 self ._ymeta .pop (t , key )
@@ -126,29 +173,7 @@ def source(self, value):
126173 self ._ystate .pop (t , key )
127174
128175 # 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 ])
152177 self ._ymeta .set (t , "metadata" , nb ["metadata" ])
153178 self ._ymeta .set (t , "nbformat" , nb ["nbformat" ])
154179 self ._ymeta .set (t , "nbformat_minor" , nb ["nbformat_minor" ])
0 commit comments