@@ -27,6 +27,51 @@ def csv_option(s):
27
27
return [p .strip () for p in s .split ("," )] if s else []
28
28
29
29
30
+ def load_content (cell , location , logger ):
31
+ if cell .arguments :
32
+ # As per 'sphinx.directives.code.LiteralInclude'
33
+ env = cell .state .document .settings .env
34
+ rel_filename , filename = env .relfn2path (cell .arguments [0 ])
35
+ env .note_dependency (rel_filename )
36
+ if cell .content :
37
+ logger .warning (
38
+ 'Ignoring inline code in Jupyter cell included from "{}"' .format (
39
+ rel_filename
40
+ ),
41
+ location = location ,
42
+ )
43
+ try :
44
+ with Path (filename ).open () as f :
45
+ content = [line .rstrip () for line in f .readlines ()]
46
+ except (IOError , OSError ):
47
+ raise IOError ("File {} not found or reading it failed" .format (filename ))
48
+ else :
49
+ cell .assert_has_content ()
50
+ content = cell .content
51
+ return content
52
+
53
+
54
+ def get_highlights (cell , content , location , logger ):
55
+ # The code fragment is taken from CodeBlock directive almost unchanged:
56
+ # https://github.com/sphinx-doc/sphinx/blob/0319faf8f1503453b6ce19020819a8cf44e39f13/sphinx/directives/code.py#L134-L148
57
+
58
+ emphasize_linespec = cell .options .get ("emphasize-lines" )
59
+ if emphasize_linespec :
60
+ nlines = len (content )
61
+ hl_lines = parselinenos (emphasize_linespec , nlines )
62
+ if any (i >= nlines for i in hl_lines ):
63
+ logger .warning (
64
+ "Line number spec is out of range(1-{}): {}" .format (
65
+ nlines , emphasize_linespec
66
+ ),
67
+ location = location ,
68
+ )
69
+ hl_lines = [i + 1 for i in hl_lines if i < nlines ]
70
+ else :
71
+ hl_lines = []
72
+ return hl_lines
73
+
74
+
30
75
class JupyterCell (Directive ):
31
76
"""Define a code cell to be later executed in a Jupyter kernel.
32
77
@@ -89,50 +134,16 @@ def run(self):
89
134
90
135
location = self .state_machine .get_source_and_line (self .lineno )
91
136
92
- if self .arguments :
93
- # As per 'sphinx.directives.code.LiteralInclude'
94
- env = self .state .document .settings .env
95
- rel_filename , filename = env .relfn2path (self .arguments [0 ])
96
- env .note_dependency (rel_filename )
97
- if self .content :
98
- logger .warning (
99
- 'Ignoring inline code in Jupyter cell included from "{}"' .format (
100
- rel_filename
101
- ),
102
- location = location ,
103
- )
104
- try :
105
- with Path (filename ).open () as f :
106
- content = [line .rstrip () for line in f .readlines ()]
107
- except (IOError , OSError ):
108
- raise IOError ("File {} not found or reading it failed" .format (filename ))
109
- else :
110
- self .assert_has_content ()
111
- content = self .content
112
-
113
- # The code fragment is taken from CodeBlock directive almost unchanged:
114
- # https://github.com/sphinx-doc/sphinx/blob/0319faf8f1503453b6ce19020819a8cf44e39f13/sphinx/directives/code.py#L134-L148
115
-
116
- emphasize_linespec = self .options .get ("emphasize-lines" )
117
- if emphasize_linespec :
118
- try :
119
- nlines = len (content )
120
- hl_lines = parselinenos (emphasize_linespec , nlines )
121
- if any (i >= nlines for i in hl_lines ):
122
- logger .warning (
123
- "Line number spec is out of range(1-{}): {}" .format (
124
- nlines , emphasize_linespec
125
- ),
126
- location = location ,
127
- )
128
- hl_lines = [i + 1 for i in hl_lines if i < nlines ]
129
- except ValueError as err :
130
- return [self .state .document .reporter .warning (err , line = self .lineno )]
131
- else :
132
- hl_lines = []
137
+ content = load_content (self , location , logger )
138
+
139
+ try :
140
+ hl_lines = get_highlights (self , content , location , logger )
141
+ except ValueError as err :
142
+ return [self .state .document .reporter .warning (err , line = self .lineno )]
133
143
134
144
# A top-level placeholder for our cell
135
145
cell_node = JupyterCellNode (
146
+ execute = True ,
136
147
hide_code = ("hide-code" in self .options ),
137
148
hide_output = ("hide-output" in self .options ),
138
149
code_below = ("code-below" in self .options ),
@@ -152,6 +163,136 @@ def run(self):
152
163
cell_node += cell_input
153
164
return [cell_node ]
154
165
166
+ class InputCell (Directive ):
167
+ """Define a code cell to be included verbatim but not executed.
168
+
169
+ Arguments
170
+ ---------
171
+ filename : str (optional)
172
+ If provided, a path to a file containing code.
173
+
174
+ Options
175
+ -------
176
+ linenos : bool
177
+ If provided, the code will be shown with line numbering.
178
+ lineno-start: nonnegative int
179
+ If provided, the code will be show with line numbering beginning from
180
+ specified line.
181
+ emphasize-lines : comma separated list of line numbers
182
+ If provided, the specified lines will be highlighted.
183
+
184
+ Content
185
+ -------
186
+ code : str
187
+ A code cell.
188
+ """
189
+
190
+ required_arguments = 0
191
+ optional_arguments = 1
192
+ final_argument_whitespace = True
193
+ has_content = True
194
+
195
+ option_spec = {
196
+ "linenos" : directives .flag ,
197
+ "lineno-start" : directives .nonnegative_int ,
198
+ "emphasize-lines" : directives .unchanged_required ,
199
+ }
200
+
201
+ def run (self ):
202
+ # This only works lazily because the logger is inited by Sphinx
203
+ from . import logger
204
+
205
+ location = self .state_machine .get_source_and_line (self .lineno )
206
+
207
+ content = load_content (self , location , logger )
208
+
209
+ try :
210
+ hl_lines = get_highlights (self , content , location , logger )
211
+ except ValueError as err :
212
+ return [self .state .document .reporter .warning (err , line = self .lineno )]
213
+
214
+ # A top-level placeholder for our cell
215
+ cell_node = JupyterCellNode (
216
+ execute = False ,
217
+ hide_code = False ,
218
+ hide_output = True ,
219
+ code_below = False ,
220
+ emphasize_lines = hl_lines ,
221
+ raises = False ,
222
+ stderr = False ,
223
+ classes = ["jupyter_cell" ],
224
+ )
225
+
226
+ # Add the input section of the cell, we'll add output when jupyter-execute cells are run
227
+ cell_input = CellInputNode (classes = ["cell_input" ])
228
+ cell_input += docutils .nodes .literal_block (
229
+ text = "\n " .join (content ),
230
+ linenos = ("linenos" in self .options ),
231
+ linenostart = (self .options .get ("lineno-start" )),
232
+ )
233
+ cell_node += cell_input
234
+ return [cell_node ]
235
+
236
+ class OutputCell (Directive ):
237
+ """Define an output cell to be included verbatim.
238
+
239
+ Arguments
240
+ ---------
241
+ filename : str (optional)
242
+ If provided, a path to a file containing output.
243
+
244
+ Content
245
+ -------
246
+ code : str
247
+ An output cell.
248
+ """
249
+
250
+ required_arguments = 0
251
+ optional_arguments = 1
252
+ final_argument_whitespace = True
253
+ has_content = True
254
+
255
+ option_spec = {}
256
+
257
+ def run (self ):
258
+ # This only works lazily because the logger is inited by Sphinx
259
+ from . import logger
260
+
261
+ location = self .state_machine .get_source_and_line (self .lineno )
262
+
263
+ content = load_content (self , location , logger )
264
+
265
+ # A top-level placeholder for our cell
266
+ cell_node = JupyterCellNode (
267
+ execute = False ,
268
+ hide_code = True ,
269
+ hide_output = False ,
270
+ code_below = False ,
271
+ emphasize_lines = [],
272
+ raises = False ,
273
+ stderr = False ,
274
+ classes = ["jupyter_cell" ],
275
+ )
276
+
277
+ # Add a blank input and the given output to the cell
278
+ cell_input = CellInputNode (classes = ["cell_input" ])
279
+ cell_input += docutils .nodes .literal_block (
280
+ text = "" ,
281
+ linenos = False ,
282
+ linenostart = None ,
283
+ )
284
+ cell_node += cell_input
285
+ content_str = "\n " .join (content )
286
+ cell_output = CellOutputNode (classes = ["cell_output" ])
287
+ cell_output += docutils .nodes .literal_block (
288
+ text = content_str ,
289
+ rawsource = content_str ,
290
+ language = "none" ,
291
+ classes = ["output" , "stream" ],
292
+ )
293
+ cell_node += cell_output
294
+ return [cell_node ]
295
+
155
296
156
297
class JupyterCellNode (docutils .nodes .container ):
157
298
"""Inserted into doctree whever a JupyterCell directive is encountered.
0 commit comments