Changeset 746
- Timestamp:
- 08/24/05 05:46:31 (3 years ago)
- Files:
-
- nbdoc/trunk/notabene/notebook.py (modified) (11 diffs)
- nbdoc/trunk/notabene/testing/test_notebook.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
nbdoc/trunk/notabene/notebook.py
r745 r746 57 57 #to be replaced by newinit 58 58 self.element = element 59 self.number = int(element.attrib['number'])60 59 61 60 @classmethod … … 64 63 #(if/)when nbshell does not suppose the current anymore, 65 64 #note: parent is a Log object, which has the 'root' as .element 66 element = ET.SubElement(parent.element, 'cell', number=str(number)) 67 return cls(element) 65 element = ET.SubElement(parent.element, 'cell') 66 instance = cls(element) 67 instance.number = number #sets the xml too via the property 68 return instance 68 69 69 70 input = property(SubelemGetter('input'), SubelemSetter('input')) … … 74 75 def get_number(self): 75 76 return int(self.element.attrib['number']) 76 77 77 def set_number(self, num): 78 78 s = str(num) 79 79 assert s.isdigit() 80 80 self.element.attrib['number'] = s 81 81 #note: this does not update the cell index in the log! 82 #so probably currently is safe only in the constructor, which is 83 #given the index number by the Log.add <- Notebook.add_cell methods 82 84 number = property(get_number, set_number) 83 85 … … 100 102 self.id = logid 101 103 self.element = ET.SubElement(parent.root, 'ipython-log', id=logid) 102 self. cells = []104 self._cells = [] #it is not safe to manipulate this from outside 103 105 104 106 def add(self, number): 105 if number == len(self. cells): #is to be put at the end107 if number == len(self._cells): #is to be put at the end 106 108 #cell = Cell(self, number) #use this when nbshell is refactored 107 109 cell = Cell.newinit(self, number) #temporary for transition 108 self.cells.append(cell) #always adds to end 109 self.element.append(cell.element) #XXX already became a subelement! 110 #should cells be a property that wraps the list and xml? 111 #dbg 112 print "NOTEBOOK Log: added cell number", number, "with number", cell.number 110 self._cells.append(cell) #always adds to end 111 #self.element.append(cell.element) #already became a subelement 112 #seems that that append call would have no effect. 113 113 return cell 114 114 115 115 else: 116 116 try: 117 self. cells[number]118 raise ValueError, 'a cell with number %d exists . note: multiple logs not implemented now.' % number117 self._cells[number] 118 raise ValueError, 'a cell with number %d exists in log id %s' % (number, self.id) 119 119 except IndexError: 120 if number > len(self. cells):120 if number > len(self._cells): 121 121 raise ValueError, "can only add at the end now. that will be fixed if needed." 122 122 else: … … 124 124 125 125 def __getitem__(self, number): 126 return self.cells[number] 127 #should None i.e. removed cells be handles specially already here? 126 return self._cells[number] 127 #should None i.e. removed cells be handled specially already here? 128 129 def __len__(self): 130 return len(self._cells) 131 132 def __iter__(self): 133 """for iterating cells in the log. filters out Nones.""" 134 cells = [cell for cell in self._cells if cell is not None] 135 return iter(cells) 128 136 129 137 def remove(self, number): 130 cell = self.cells[number] 131 self.cells[number] = None #XXX probably not handled properly elsewhere 138 cell = self._cells[number] 139 if cell is self._cells[-1]: #if is last element 140 self._cells.pop() #remove 141 while self._cells[-1] is None: #if the previous, next. prev etc 142 self._cells.pop() #remove all Nones at the end 143 else: 144 self._cells[number] = None #XXX these gaps not handled everywhere 132 145 self.element.remove(cell.element) 133 146 … … 221 234 """Add a log element. 222 235 223 id is a unique identifier. No other XML element in this file should have 224 the same id. 225 """ 226 self.logs[id] = Log(self, id) 236 id is a unique identifier. No other XML element in this file should have the same id. 237 """ 238 #should the uniqueness of the id be checked here? 239 log = Log(self, id) #this creates a subelement to self.root 240 self.logs[id] = log 241 return log 227 242 228 243 def get_log(self, logid='default-log'): … … 238 253 raise ValueError('No log with id="%s"' % logid) 239 254 255 def newget_log(self, logid='default-log'): 256 #useful for getting a default log without id, 257 #even if/when self.logs is exposed for id-using getting of logs. 258 #to replace current get_log when that is not used anymore 259 if logid in self.logs: 260 return self.logs[logid] 261 else: 262 raise ValueError('No log with id="%s"' % logid) 263 240 264 def oldget_cell(self, number, logid='default-log'): 241 265 #note: Tzanko considers this too slow for nbshell … … 247 271 return ET.SubElement(log, 'cell', number=str(number)) 248 272 249 def add_cell(self, number , logid='default-log'):273 def add_cell(self, number=None, logid='default-log'): 250 274 log = self.logs[logid] 275 if number is None: #add to end by default 276 #not used by nbshell currently, 277 #but handy for at least tests.. 278 number = len(log) 251 279 cell = log.add(number) 252 280 return cell … … 256 284 return log[number] 257 285 258 def get_last_cell(self, logid='default-log'):286 def get_last_cell(self, logid='default-log'): 259 287 log = self.logs[logid] 260 288 return log[-1] … … 400 428 #XXX new for the new cell and log system, untested 401 429 log = self.logs[logid] 402 return '\n'.join(cell.get_input(specials) for cell in log .cells)430 return '\n'.join(cell.get_input(specials) for cell in log) 403 431 404 432 def start_checkpointing(self, checkpoint=10): … … 594 622 sheet = ET.Element('sheet') 595 623 block = ET.SubElement(sheet, 'ipython-block', logid=logid) 596 for cell in log .cells:624 for cell in log: 597 625 #dbg 598 626 print "*NEW*DEFAULT SHEET: cell", cell nbdoc/trunk/notabene/testing/test_notebook.py
r742 r746 195 195 196 196 def test_log(): 197 nb = test_new() 198 log = nb.get_log() 199 197 nb = test_new() #adds a default log 198 logelement = nb.get_log() #old way, to be removed? 199 log = nb.newget_log() 200 201 #using the default log via notebook methods 200 202 py.test.raises(IndexError, "nb.get_cell(1)") #should not create anymore 201 203 py.test.raises(ValueError, "nb.add_cell(15)") #can only add to end now 202 cell = nb.add_cell(0) 204 cell = nb.add_cell(0) #is added to default log 203 205 assert cell is nb.get_cell(0) #this should be the same one 204 206 assert cell.input is None 205 207 assert cell.output is None 206 208 209 #multiple log support 210 assert py.test.raises(ValueError, "nb.get_log('log2')") #nonexisting 211 log2 = nb.add_log('log2') 212 assert log2.element is nb.get_log('log2') #backwards compat. for nbshell 213 assert log2 is nb.logs['log2'] #this is how Notebook does internally. 214 #ok to expose to outside too? 215 cell20 = nb.add_cell(0, 'log2') 216 cell21 = log2.add(1) #also this is possible. ok? 217 assert cell20 is nb.get_cell(0, 'log2') 218 assert cell21 is nb.get_cell(1, 'log2') 219 assert cell21.number == 1 220 assert cell20 is log2[0] #again: Notebook does this. ok from outside? 221 222 #back to default log, to test cell functionality 207 223 python_in = "3 // 2" 208 224 python_out = "1" … … 215 231 assert cell.element.find('input').text == python_in 216 232 assert cell.element.find('output').text == python_out 217 218 #note: the do-specials in original Cell not there 233 #nbshell also calls methods of xml elements 234 #so they need to be exposed like this, 235 #but at least in some cases the use should be limited to querying 236 #.. altough manipulating some attributes is safe, 237 #but e.g. changing the number attribute of a cell is not, 238 #even though it is a property that wraps xml, 239 #because Logs also have an index of them too. 240 241 #note: the do-specials in original Cell not in the new system (yet) 219 242 220 243 #should be standard elements too? … … 232 255 assert cell.element.find('stderr').text == stderrtext 233 256 257 #(default) sheet test 234 258 sheet = nb.default_sheet() 235 259 ipblock = sheet.find('ipython-block') … … 239 263 found.add(ic.attrib['type']) 240 264 assert found == set(['input', 'stdout', 'stderr', 'output']) 241 242 243 244 245 246 265 #cell.get_sheet_tags lacks tests 266 267 #cell removal/deletion 268 cell2 = nb.add_cell() 269 cell3 = nb.add_cell() 270 for number, cell in enumerate(log): 271 assert number == cell.number 272 number = cell2.number 273 log.remove(number) 274 assert log[number] is None #is not removed 'cause is in the middle 275 numcells = log.element.xpath('./cell[@number=%s]' % number) 276 assert len(numcells) == 0 #the cell was actually removed from xml 277 278 #so far so good, but then all kinds of strange things start to happen: 279 assert nb.get_cell(number) is None #does this make sense? 280 #assert nb.get_last_cell() is None #this certainly does not! 281 #so log.remove is fixed to handle it: 282 lastcell = nb.get_last_cell() 283 assert lastcell is log[-1] #nice, no? this also public.. 284 nb.remove_cell(lastcell.number) 285 assert nb.get_last_cell() is not None 286 for cell in log: 287 print etree.tostring(cell.element) 288 289 #should all trailing Nones be removed? 290 #probably so, to make this succeed: 291 cell2 = nb.add_cell() 292 cell3 = nb.add_cell() 293 cell4 = nb.add_cell() 294 nb.remove_cell(cell2.number) 295 nb.remove_cell(cell3.number) 296 nb.remove_cell(cell4.number) 297 assert nb.get_last_cell() is not None 298 299 300 301 302 303 304
