Skip to content

Commit 987820b

Browse files
authored
Merge pull request #113 from seanpue/master
Fix for #110 and added :lineno-start: directive
2 parents 970097e + 7b222ec commit 987820b

File tree

4 files changed

+120
-37
lines changed

4 files changed

+120
-37
lines changed

doc/source/index.rst

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,12 @@ produces:
177177

178178
You may also add *line numbers* to the source code with ``:linenos:``::
179179

180-
.. jupyter-execute::
181-
:linenos:
180+
.. jupyter-execute::
181+
:linenos:
182182

183-
print('A')
184-
print('B')
185-
print('C')
183+
print('A')
184+
print('B')
185+
print('C')
186186

187187
produces:
188188

@@ -193,6 +193,25 @@ produces:
193193
print('B')
194194
print('C')
195195

196+
To add *line numbers from a specific line* to the source code, use the
197+
``lineno-start`` directive::
198+
199+
.. jupyter-execute::
200+
:lineno-start: 7
201+
202+
print('A')
203+
print('B')
204+
print('C')
205+
206+
produces:
207+
208+
.. jupyter-execute::
209+
:lineno-start: 7
210+
211+
print('A')
212+
print('B')
213+
print('C')
214+
196215
You may also emphasize particular lines in the source code with ``:emphasize-lines:``::
197216

198217
.. jupyter-execute::
@@ -209,6 +228,7 @@ You may also emphasize particular lines in the source code with ``:emphasize-lin
209228
produces:
210229

211230
.. jupyter-execute::
231+
:lineno-start: 2
212232
:emphasize-lines: 2,5-6
213233

214234
d = {
@@ -379,4 +399,5 @@ jupyter_sphinx_linenos
379399

380400
jupyter_sphinx_continue_linenos
381401

382-
Whether to show continuous line numbering in all ``jupyter-execute`` sources.
402+
Whether to continue line numbering from previous cell in all ``jupyter-execute``
403+
sources.

jupyter_sphinx/ast.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class JupyterCell(Directive):
4545
If provided, the code will be shown below the cell output.
4646
linenos : bool
4747
If provided, the code will be shown with line numbering.
48+
lineno-start: nonnegative int
49+
If provided, the code will be show with line numbering beginning from
50+
specified line.
4851
emphasize-lines : comma separated list of line numbers
4952
If provided, the specified lines will be highlighted.
5053
raises : comma separated list of exception types
@@ -70,6 +73,7 @@ class JupyterCell(Directive):
7073
"hide-output": directives.flag,
7174
"code-below": directives.flag,
7275
"linenos": directives.flag,
76+
"lineno-start": directives.nonnegative_int,
7377
"emphasize-lines": directives.unchanged_required,
7478
"raises": csv_option,
7579
"stderr": directives.flag,
@@ -78,6 +82,7 @@ class JupyterCell(Directive):
7882
def run(self):
7983
# This only works lazily because the logger is inited by Sphinx
8084
from . import logger
85+
8186
location = self.state_machine.get_source_and_line(self.lineno)
8287

8388
if self.arguments:
@@ -103,6 +108,7 @@ def run(self):
103108

104109
# The code fragment is taken from CodeBlock directive almost unchanged:
105110
# https://github.com/sphinx-doc/sphinx/blob/0319faf8f1503453b6ce19020819a8cf44e39f13/sphinx/directives/code.py#L134-L148
111+
106112
emphasize_linespec = self.options.get("emphasize-lines")
107113
if emphasize_linespec:
108114
try:
@@ -129,6 +135,7 @@ def run(self):
129135
hide_output=("hide-output" in self.options),
130136
code_below=("code-below" in self.options),
131137
linenos=("linenos" in self.options),
138+
linenostart=(self.options.get("lineno-start")),
132139
emphasize_lines=hl_lines,
133140
raises=self.options.get("raises"),
134141
stderr=("stderr" in self.options),

jupyter_sphinx/execute.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -171,20 +171,25 @@ def apply(self):
171171
source = node.children[0]
172172
source.attributes["language"] = lexer
173173

174-
# Add line numbers to code cells if jupyter_sphinx_linenos or
175-
# jupyter_sphinx_continue_linenos are set in the configuration,
176-
# or the linenos directive is set.
177-
# Update current line numbers from cell if jupyter_sphinx_continue_linenos
178-
# is set.
174+
# Add line numbering
175+
179176
linenostart = 1
177+
180178
for node in nodes:
181179
source = node.children[0]
182180
nlines = source.rawsource.count("\n") + 1
181+
show_numbering = (
182+
linenos_config or node["linenos"] or node["linenostart"]
183+
)
183184

184-
if linenos_config or continue_linenos or node["linenos"]:
185+
if show_numbering:
185186
source["linenos"] = True
186-
if continue_linenos:
187-
source["highlight_args"] = {"linenostart": linenostart}
187+
if node["linenostart"]:
188+
linenostart = node["linenostart"]
189+
if node["linenostart"] or continue_linenos:
190+
source["highlight_args"] = {"linenostart": linenostart}
191+
else:
192+
linenostart = 1
188193
linenostart += nlines
189194

190195
hl_lines = node["emphasize_lines"]
@@ -275,6 +280,7 @@ def setup(app):
275280
"""
276281
# To avoid circular imports we'll lazily import
277282
from . import setup as jssetup
283+
278284
js.logger.warning(
279285
(
280286
"`jupyter-sphinx` was initialized with the "

tests/test_execute.py

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ def doctree():
2424
apps = []
2525
syspath = sys.path[:]
2626

27-
def doctree(source, config=None, return_warnings=False, entrypoint="jupyter_sphinx"):
27+
def doctree(
28+
source, config=None, return_warnings=False, entrypoint="jupyter_sphinx"
29+
):
2830
src_dir = tempfile.mkdtemp()
2931
source_trees.append(src_dir)
3032
with open(os.path.join(src_dir, "conf.py"), "w") as f:
@@ -61,7 +63,7 @@ def test_basic(doctree):
6163
2 + 2
6264
"""
6365
tree = doctree(source)
64-
cell, = tree.traverse(JupyterCellNode)
66+
(cell,) = tree.traverse(JupyterCellNode)
6567
assert cell.attributes["code_below"] is False
6668
assert cell.attributes["hide_code"] is False
6769
assert cell.attributes["hide_output"] is False
@@ -77,7 +79,7 @@ def test_basic_old_entrypoint(doctree):
7779
2 + 2
7880
"""
7981
tree = doctree(source, entrypoint="jupyter_sphinx.execute")
80-
cell, = tree.traverse(JupyterCellNode)
82+
(cell,) = tree.traverse(JupyterCellNode)
8183
assert cell.attributes["code_below"] is False
8284
assert cell.attributes["hide_code"] is False
8385
assert cell.attributes["hide_output"] is False
@@ -94,7 +96,7 @@ def test_hide_output(doctree):
9496
2 + 2
9597
"""
9698
tree = doctree(source)
97-
cell, = tree.traverse(JupyterCellNode)
99+
(cell,) = tree.traverse(JupyterCellNode)
98100
assert cell.attributes["hide_output"] is True
99101
assert len(cell.children) == 1
100102
assert cell.children[0].rawsource.strip() == "2 + 2"
@@ -108,7 +110,7 @@ def test_hide_code(doctree):
108110
2 + 2
109111
"""
110112
tree = doctree(source)
111-
cell, = tree.traverse(JupyterCellNode)
113+
(cell,) = tree.traverse(JupyterCellNode)
112114
assert cell.attributes["hide_code"] is True
113115
assert len(cell.children) == 1
114116
assert cell.children[0].rawsource.strip() == "4"
@@ -122,7 +124,7 @@ def test_code_below(doctree):
122124
2 + 2
123125
"""
124126
tree = doctree(source)
125-
cell, = tree.traverse(JupyterCellNode)
127+
(cell,) = tree.traverse(JupyterCellNode)
126128
assert cell.attributes["code_below"] is True
127129
assert cell.children[0].rawsource.strip() == "4"
128130
assert cell.children[1].rawsource.strip() == "2 + 2"
@@ -136,7 +138,7 @@ def test_linenos(doctree):
136138
2 + 2
137139
"""
138140
tree = doctree(source)
139-
cell, = tree.traverse(JupyterCellNode)
141+
(cell,) = tree.traverse(JupyterCellNode)
140142
assert cell.attributes["linenos"] is True
141143
assert len(cell.children) == 2
142144
assert cell.children[0].rawsource.strip() == "2 + 2"
@@ -149,7 +151,7 @@ def test_linenos(doctree):
149151
2 + 2
150152
"""
151153
tree = doctree(source)
152-
cell, = tree.traverse(JupyterCellNode)
154+
(cell,) = tree.traverse(JupyterCellNode)
153155
assert len(cell.children) == 2
154156
assert cell.attributes["linenos"] is True
155157

@@ -161,14 +163,29 @@ def test_linenos_conf_option(doctree):
161163
2 + 2
162164
"""
163165
tree = doctree(source, config="jupyter_sphinx_linenos = True")
164-
cell, = tree.traverse(JupyterCellNode)
166+
(cell,) = tree.traverse(JupyterCellNode)
165167
assert cell.children[0].attributes["linenos"]
166168
assert "highlight_args" not in cell.children[0].attributes
167169
assert cell.children[0].rawsource.strip() == "2 + 2"
168170
assert cell.children[1].rawsource.strip() == "4"
169171

170172

171173
def test_continue_linenos_conf_option(doctree):
174+
# Test no linenumbering without linenos config or lineno-start directive
175+
source = """
176+
.. jupyter-execute::
177+
178+
2 + 2
179+
180+
"""
181+
182+
tree = doctree(source, config="jupyter_sphinx_continue_linenos = True")
183+
(cell,) = tree.traverse(JupyterCellNode)
184+
assert "linenos" not in cell.children[0].attributes
185+
assert cell.children[0].rawsource.strip() == "2 + 2"
186+
assert cell.children[1].rawsource.strip() == "4"
187+
188+
# Test continuous line numbering
172189
source = """
173190
.. jupyter-execute::
174191
@@ -179,11 +196,15 @@ def test_continue_linenos_conf_option(doctree):
179196
3 + 3
180197
181198
"""
182-
continue_linenos_config = "jupyter_sphinx_continue_linenos = True"
183-
tree = doctree(source, config=continue_linenos_config)
199+
200+
tree = doctree(
201+
source,
202+
config="jupyter_sphinx_linenos = True\n"
203+
"jupyter_sphinx_continue_linenos = True",
204+
)
205+
184206
cell0, cell1 = tree.traverse(JupyterCellNode)
185207
assert cell0.children[0].attributes["linenos"]
186-
assert cell0.children[0].attributes["highlight_args"]["linenostart"] == 1
187208
assert cell0.children[0].rawsource.strip() == "2 + 2"
188209
assert cell0.children[1].rawsource.strip() == "4"
189210

@@ -192,6 +213,34 @@ def test_continue_linenos_conf_option(doctree):
192213
assert cell1.children[0].rawsource.strip() == "3 + 3"
193214
assert cell1.children[1].rawsource.strip() == "6"
194215

216+
# Line number should continue after lineno-start option
217+
218+
source = """
219+
.. jupyter-execute::
220+
:lineno-start: 7
221+
222+
2 + 2
223+
224+
.. jupyter-execute::
225+
226+
3 + 3
227+
228+
"""
229+
tree = doctree(
230+
source,
231+
config="jupyter_sphinx_linenos = True\n"
232+
"jupyter_sphinx_continue_linenos = True",
233+
)
234+
cell0, cell1 = tree.traverse(JupyterCellNode)
235+
assert cell0.children[0].attributes["highlight_args"]["linenostart"] == 7
236+
assert cell0.children[0].rawsource.strip() == "2 + 2"
237+
assert cell0.children[1].rawsource.strip() == "4"
238+
239+
assert cell1.children[0].attributes["linenos"]
240+
assert cell1.children[0].attributes["highlight_args"]["linenostart"] == 8
241+
assert cell1.children[0].rawsource.strip() == "3 + 3"
242+
assert cell1.children[1].rawsource.strip() == "6"
243+
195244

196245
def test_emphasize_lines(doctree):
197246
source = """
@@ -272,7 +321,7 @@ def test_raises(doctree):
272321
raise ValueError()
273322
"""
274323
tree = doctree(source)
275-
cell, = tree.traverse(JupyterCellNode)
324+
(cell,) = tree.traverse(JupyterCellNode)
276325
assert "ValueError" in cell.children[1].rawsource
277326

278327
source = """
@@ -282,7 +331,7 @@ def test_raises(doctree):
282331
raise ValueError()
283332
"""
284333
tree = doctree(source)
285-
cell, = tree.traverse(JupyterCellNode)
334+
(cell,) = tree.traverse(JupyterCellNode)
286335
assert "ValueError" in cell.children[1].rawsource
287336

288337

@@ -306,8 +355,8 @@ def test_javascript(doctree):
306355
Javascript('window.alert("Hello world!")')
307356
"""
308357
tree = doctree(source)
309-
node, = list(tree.traverse(raw))
310-
text, = node.children
358+
(node,) = list(tree.traverse(raw))
359+
(text,) = node.children
311360
assert "world" in text
312361

313362

@@ -318,7 +367,7 @@ def test_stdout(doctree):
318367
print('hello world')
319368
"""
320369
tree = doctree(source)
321-
cell, = tree.traverse(JupyterCellNode)
370+
(cell,) = tree.traverse(JupyterCellNode)
322371
assert len(cell.children) == 2
323372
assert cell.children[1].rawsource.strip() == "hello world"
324373

@@ -333,7 +382,7 @@ def test_stderr(doctree):
333382

334383
tree, warnings = doctree(source, return_warnings=True)
335384
assert "hello world" in warnings
336-
cell, = tree.traverse(JupyterCellNode)
385+
(cell,) = tree.traverse(JupyterCellNode)
337386
assert len(cell.children) == 1 # no output
338387

339388
source = """
@@ -344,7 +393,7 @@ def test_stderr(doctree):
344393
print('hello world', file=sys.stderr)
345394
"""
346395
tree = doctree(source)
347-
cell, = tree.traverse(JupyterCellNode)
396+
(cell,) = tree.traverse(JupyterCellNode)
348397
assert len(cell.children) == 2
349398
assert "stderr" in cell.children[1].attributes["classes"]
350399
assert cell.children[1].astext().strip() == "hello world"
@@ -361,7 +410,7 @@ def test_thebe_hide_output(doctree):
361410
2 + 2
362411
"""
363412
tree = doctree(source, thebe_config)
364-
cell, = tree.traverse(JupyterCellNode)
413+
(cell,) = tree.traverse(JupyterCellNode)
365414
assert cell.attributes["hide_output"] is True
366415
assert len(cell.children) == 1
367416

@@ -379,7 +428,7 @@ def test_thebe_hide_code(doctree):
379428
2 + 2
380429
"""
381430
tree = doctree(source, thebe_config)
382-
cell, = tree.traverse(JupyterCellNode)
431+
(cell,) = tree.traverse(JupyterCellNode)
383432
assert cell.attributes["hide_code"] is True
384433
assert len(cell.children) == 2
385434

@@ -403,7 +452,7 @@ def test_thebe_code_below(doctree):
403452
2 + 2
404453
"""
405454
tree = doctree(source, thebe_config)
406-
cell, = tree.traverse(JupyterCellNode)
455+
(cell,) = tree.traverse(JupyterCellNode)
407456
assert cell.attributes["code_below"] is True
408457

409458
output = cell.children[0]
@@ -461,5 +510,5 @@ def test_latex(doctree):
461510

462511
for start, end in delimiter_pairs:
463512
tree = doctree(source.format(start, end))
464-
cell, = tree.traverse(JupyterCellNode)
513+
(cell,) = tree.traverse(JupyterCellNode)
465514
assert cell.children[1].astext() == r"\int"

0 commit comments

Comments
 (0)