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
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
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# -----------------------------------------------------------------------------
18from __future__ import annotations
20import re
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."""
44class PyReader(NotebookReader):
45 """A python notebook reader."""
47 def reads(self, s, **kwargs):
48 """Convert a string to a notebook"""
49 return self.to_notebook(s, **kwargs)
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])
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)
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
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
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")
164class PyWriter(NotebookWriter):
165 """A Python notebook writer."""
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)
213_reader = PyReader()
214_writer = PyWriter()
216reads = _reader.reads
217read = _reader.read
218to_notebook = _reader.to_notebook
219write = _writer.write
220writes = _writer.writes