Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/nbformat/v3/nbpy.py: 14%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

155 statements  

1"""Read and write notebooks as regular .py files. 

2 

3Authors: 

4 

5* Brian Granger 

6""" 

7 

8# ----------------------------------------------------------------------------- 

9# Copyright (C) 2008-2011 The IPython Development Team 

10# 

11# Distributed under the terms of the BSD License. The full license is in 

12# the file LICENSE, distributed as part of this software. 

13# ----------------------------------------------------------------------------- 

14 

15# ----------------------------------------------------------------------------- 

16# Imports 

17# ----------------------------------------------------------------------------- 

18from __future__ import annotations 

19 

20import re 

21 

22from .nbbase import ( 

23 nbformat, 

24 nbformat_minor, 

25 new_code_cell, 

26 new_heading_cell, 

27 new_notebook, 

28 new_text_cell, 

29 new_worksheet, 

30) 

31from .rwbase import NotebookReader, NotebookWriter 

32 

33# ----------------------------------------------------------------------------- 

34# Code 

35# ----------------------------------------------------------------------------- 

36 

37_encoding_declaration_re = re.compile(r"^#.*coding[:=]\s*([-\w.]+)") 

38 

39 

40class PyReaderError(Exception): 

41 """An error raised for a pyreader error.""" 

42 

43 

44class PyReader(NotebookReader): 

45 """A python notebook reader.""" 

46 

47 def reads(self, s, **kwargs): 

48 """Convert a string to a notebook""" 

49 return self.to_notebook(s, **kwargs) 

50 

51 def to_notebook(self, s, **kwargs): 

52 """Convert a string to a notebook""" 

53 lines = s.splitlines() 

54 cells = [] 

55 cell_lines: list[str] = [] 

56 kwargs = {} 

57 state = "codecell" 

58 for line in lines: 

59 if line.startswith("# <nbformat>") or _encoding_declaration_re.match(line): 

60 pass 

61 elif line.startswith("# <codecell>"): 

62 cell = self.new_cell(state, cell_lines, **kwargs) 

63 if cell is not None: 

64 cells.append(cell) 

65 state = "codecell" 

66 cell_lines = [] 

67 kwargs = {} 

68 elif line.startswith("# <htmlcell>"): 

69 cell = self.new_cell(state, cell_lines, **kwargs) 

70 if cell is not None: 

71 cells.append(cell) 

72 state = "htmlcell" 

73 cell_lines = [] 

74 kwargs = {} 

75 elif line.startswith("# <markdowncell>"): 

76 cell = self.new_cell(state, cell_lines, **kwargs) 

77 if cell is not None: 

78 cells.append(cell) 

79 state = "markdowncell" 

80 cell_lines = [] 

81 kwargs = {} 

82 # VERSIONHACK: plaintext -> raw 

83 elif line.startswith(("# <rawcell>", "# <plaintextcell>")): 

84 cell = self.new_cell(state, cell_lines, **kwargs) 

85 if cell is not None: 

86 cells.append(cell) 

87 state = "rawcell" 

88 cell_lines = [] 

89 kwargs = {} 

90 elif line.startswith("# <headingcell"): 

91 cell = self.new_cell(state, cell_lines, **kwargs) 

92 if cell is not None: 

93 cells.append(cell) 

94 cell_lines = [] 

95 m = re.match(r"# <headingcell level=(?P<level>\d)>", line) 

96 if m is not None: 

97 state = "headingcell" 

98 kwargs = {} 

99 kwargs["level"] = int(m.group("level")) 

100 else: 

101 state = "codecell" 

102 kwargs = {} 

103 cell_lines = [] 

104 else: 

105 cell_lines.append(line) 

106 if cell_lines and state == "codecell": 

107 cell = self.new_cell(state, cell_lines) 

108 if cell is not None: 

109 cells.append(cell) 

110 ws = new_worksheet(cells=cells) 

111 return new_notebook(worksheets=[ws]) 

112 

113 def new_cell(self, state, lines, **kwargs): 

114 """Create a new cell.""" 

115 if state == "codecell": 

116 input_ = "\n".join(lines) 

117 input_ = input_.strip("\n") 

118 if input_: 

119 return new_code_cell(input=input_) 

120 elif state == "htmlcell": 

121 text = self._remove_comments(lines) 

122 if text: 

123 return new_text_cell("html", source=text) 

124 elif state == "markdowncell": 

125 text = self._remove_comments(lines) 

126 if text: 

127 return new_text_cell("markdown", source=text) 

128 elif state == "rawcell": 

129 text = self._remove_comments(lines) 

130 if text: 

131 return new_text_cell("raw", source=text) 

132 elif state == "headingcell": 

133 text = self._remove_comments(lines) 

134 level = kwargs.get("level", 1) 

135 if text: 

136 return new_heading_cell(source=text, level=level) 

137 

138 def _remove_comments(self, lines): 

139 new_lines = [] 

140 for line in lines: 

141 if line.startswith("#"): 

142 new_lines.append(line[2:]) 

143 else: 

144 new_lines.append(line) 

145 text = "\n".join(new_lines) 

146 text = text.strip("\n") 

147 return text # noqa: RET504 

148 

149 def split_lines_into_blocks(self, lines): 

150 """Split lines into code blocks.""" 

151 if len(lines) == 1: 

152 yield lines[0] 

153 raise StopIteration() 

154 import ast 

155 

156 source = "\n".join(lines) 

157 code = ast.parse(source) 

158 starts = [x.lineno - 1 for x in code.body] 

159 for i in range(len(starts) - 1): 

160 yield "\n".join(lines[starts[i] : starts[i + 1]]).strip("\n") 

161 yield "\n".join(lines[starts[-1] :]).strip("\n") 

162 

163 

164class PyWriter(NotebookWriter): 

165 """A Python notebook writer.""" 

166 

167 def writes(self, nb, **kwargs): 

168 """Convert a notebook to a string.""" 

169 lines = ["# -*- coding: utf-8 -*-"] 

170 lines.extend( 

171 [ 

172 "# <nbformat>%i.%i</nbformat>" % (nbformat, nbformat_minor), 

173 "", 

174 ] 

175 ) 

176 for ws in nb.worksheets: 

177 for cell in ws.cells: 

178 if cell.cell_type == "code": 

179 input_ = cell.get("input") 

180 if input_ is not None: 

181 lines.extend(["# <codecell>", ""]) 

182 lines.extend(input_.splitlines()) 

183 lines.append("") 

184 elif cell.cell_type == "html": 

185 input_ = cell.get("source") 

186 if input_ is not None: 

187 lines.extend(["# <htmlcell>", ""]) 

188 lines.extend(["# " + line for line in input_.splitlines()]) 

189 lines.append("") 

190 elif cell.cell_type == "markdown": 

191 input_ = cell.get("source") 

192 if input_ is not None: 

193 lines.extend(["# <markdowncell>", ""]) 

194 lines.extend(["# " + line for line in input_.splitlines()]) 

195 lines.append("") 

196 elif cell.cell_type == "raw": 

197 input_ = cell.get("source") 

198 if input_ is not None: 

199 lines.extend(["# <rawcell>", ""]) 

200 lines.extend(["# " + line for line in input_.splitlines()]) 

201 lines.append("") 

202 elif cell.cell_type == "heading": 

203 input_ = cell.get("source") 

204 level = cell.get("level", 1) 

205 if input_ is not None: 

206 lines.extend(["# <headingcell level=%s>" % level, ""]) 

207 lines.extend(["# " + line for line in input_.splitlines()]) 

208 lines.append("") 

209 lines.append("") 

210 return "\n".join(lines) 

211 

212 

213_reader = PyReader() 

214_writer = PyWriter() 

215 

216reads = _reader.reads 

217read = _reader.read 

218to_notebook = _reader.to_notebook 

219write = _writer.write 

220writes = _writer.writes