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

157 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-01 06:54 +0000

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# ----------------------------------------------------------------------------- 

18 

19import re 

20from typing import List 

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 pass 

44 

45 

46class PyReader(NotebookReader): 

47 """A python notebook reader.""" 

48 

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

50 """Convert a string to a notebook""" 

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

52 

53 def to_notebook(self, s, **kwargs): # noqa 

54 """Convert a string to a notebook""" 

55 lines = s.splitlines() 

56 cells = [] 

57 cell_lines: List[str] = [] 

58 kwargs = {} 

59 state = "codecell" 

60 for line in lines: 

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

62 pass 

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

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

65 if cell is not None: 

66 cells.append(cell) 

67 state = "codecell" 

68 cell_lines = [] 

69 kwargs = {} 

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

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

72 if cell is not None: 

73 cells.append(cell) 

74 state = "htmlcell" 

75 cell_lines = [] 

76 kwargs = {} 

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

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

79 if cell is not None: 

80 cells.append(cell) 

81 state = "markdowncell" 

82 cell_lines = [] 

83 kwargs = {} 

84 # VERSIONHACK: plaintext -> raw 

85 elif line.startswith("# <rawcell>") or line.startswith("# <plaintextcell>"): 

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

87 if cell is not None: 

88 cells.append(cell) 

89 state = "rawcell" 

90 cell_lines = [] 

91 kwargs = {} 

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

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

94 if cell is not None: 

95 cells.append(cell) 

96 cell_lines = [] 

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

98 if m is not None: 

99 state = "headingcell" 

100 kwargs = {} 

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

102 else: 

103 state = "codecell" 

104 kwargs = {} 

105 cell_lines = [] 

106 else: 

107 cell_lines.append(line) 

108 if cell_lines and state == "codecell": 

109 cell = self.new_cell(state, cell_lines) 

110 if cell is not None: 

111 cells.append(cell) 

112 ws = new_worksheet(cells=cells) 

113 nb = new_notebook(worksheets=[ws]) 

114 return nb 

115 

116 def new_cell(self, state, lines, **kwargs): # noqa 

117 """Create a new cell.""" 

118 if state == "codecell": 

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

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

121 if input_: 

122 return new_code_cell(input=input_) 

123 elif state == "htmlcell": 

124 text = self._remove_comments(lines) 

125 if text: 

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

127 elif state == "markdowncell": 

128 text = self._remove_comments(lines) 

129 if text: 

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

131 elif state == "rawcell": 

132 text = self._remove_comments(lines) 

133 if text: 

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

135 elif state == "headingcell": 

136 text = self._remove_comments(lines) 

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

138 if text: 

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

140 

141 def _remove_comments(self, lines): 

142 new_lines = [] 

143 for line in lines: 

144 if line.startswith("#"): 

145 new_lines.append(line[2:]) 

146 else: 

147 new_lines.append(line) 

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

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

150 return text 

151 

152 def split_lines_into_blocks(self, lines): 

153 """Split lines into code blocks.""" 

154 if len(lines) == 1: 

155 yield lines[0] 

156 raise StopIteration() 

157 import ast 

158 

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

160 code = ast.parse(source) 

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

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

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

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

165 

166 

167class PyWriter(NotebookWriter): 

168 """A Python notebook writer.""" 

169 

170 def writes(self, nb, **kwargs): # noqa 

171 """Convert a notebook to a string.""" 

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

173 lines.extend( 

174 [ 

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

176 "", 

177 ] 

178 ) 

179 for ws in nb.worksheets: 

180 for cell in ws.cells: 

181 if cell.cell_type == "code": 

182 input_ = cell.get("input") 

183 if input_ is not None: 

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

185 lines.extend(input_.splitlines()) 

186 lines.append("") 

187 elif cell.cell_type == "html": 

188 input_ = cell.get("source") 

189 if input_ is not None: 

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

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

192 lines.append("") 

193 elif cell.cell_type == "markdown": 

194 input_ = cell.get("source") 

195 if input_ is not None: 

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

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

198 lines.append("") 

199 elif cell.cell_type == "raw": 

200 input_ = cell.get("source") 

201 if input_ is not None: 

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

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

204 lines.append("") 

205 elif cell.cell_type == "heading": 

206 input_ = cell.get("source") 

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

208 if input_ is not None: 

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

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

211 lines.append("") 

212 lines.append("") 

213 return "\n".join(lines) 

214 

215 

216_reader = PyReader() 

217_writer = PyWriter() 

218 

219reads = _reader.reads 

220read = _reader.read 

221to_notebook = _reader.to_notebook 

222write = _writer.write 

223writes = _writer.writes