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
« 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.
3Authors:
5* Brian Granger
6"""
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# -----------------------------------------------------------------------------
15# -----------------------------------------------------------------------------
16# Imports
17# -----------------------------------------------------------------------------
19import re
20from typing import List
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
33# -----------------------------------------------------------------------------
34# Code
35# -----------------------------------------------------------------------------
37_encoding_declaration_re = re.compile(r"^#.*coding[:=]\s*([-\w.]+)")
40class PyReaderError(Exception):
41 """An error raised for a pyreader error."""
43 pass
46class PyReader(NotebookReader):
47 """A python notebook reader."""
49 def reads(self, s, **kwargs):
50 """Convert a string to a notebook"""
51 return self.to_notebook(s, **kwargs)
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
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)
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
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
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")
167class PyWriter(NotebookWriter):
168 """A Python notebook writer."""
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)
216_reader = PyReader()
217_writer = PyWriter()
219reads = _reader.reads
220read = _reader.read
221to_notebook = _reader.to_notebook
222write = _writer.write
223writes = _writer.writes