sphinx-examples-as-code 0.4.0__tar.gz → 0.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/PKG-INFO +6 -4
  2. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/README.md +5 -3
  3. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/sphinx_examples_as_code/__init__.py +31 -2
  4. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/sphinx_examples_as_code/_version.py +3 -3
  5. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/sphinx_examples_as_code.egg-info/PKG-INFO +6 -4
  6. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/sphinx_examples_as_code.egg-info/scm_version.json +2 -2
  7. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/test_sphinx_examples_as_code.py +79 -0
  8. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/test_tinypages.py +4 -3
  9. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/.github/dependabot.yml +0 -0
  10. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/.github/release.yml +0 -0
  11. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/.github/workflows/ci.yml +0 -0
  12. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/.gitignore +0 -0
  13. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/.pre-commit-config.yaml +0 -0
  14. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/LICENSE +0 -0
  15. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/pyproject.toml +0 -0
  16. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/setup.cfg +0 -0
  17. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/sphinx_examples_as_code.egg-info/SOURCES.txt +0 -0
  18. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/sphinx_examples_as_code.egg-info/dependency_links.txt +0 -0
  19. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/sphinx_examples_as_code.egg-info/requires.txt +0 -0
  20. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/sphinx_examples_as_code.egg-info/scm_file_list.json +0 -0
  21. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/sphinx_examples_as_code.egg-info/top_level.txt +0 -0
  22. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/gallery_fixture/conf.py +0 -0
  23. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/gallery_fixture/examples/GALLERY_HEADER.rst +0 -0
  24. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/gallery_fixture/examples/plot_minimal.py +0 -0
  25. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/gallery_fixture/index.rst +0 -0
  26. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/heading_level_fixture/conf.py +0 -0
  27. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/heading_level_fixture/examples/GALLERY_HEADER.rst +0 -0
  28. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/heading_level_fixture/examples/plot_reused_level.py +0 -0
  29. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/heading_level_fixture/examples/plot_three_levels.py +0 -0
  30. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/heading_level_fixture/index.rst +0 -0
  31. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/single_function_fixture/conf.py +0 -0
  32. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/single_function_fixture/index.rst +0 -0
  33. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/single_function_fixture/mymodule.py +0 -0
  34. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/test_gallery_downloads.py +0 -0
  35. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/test_heading_level_reuse.py +0 -0
  36. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/test_single_function_page.py +0 -0
  37. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/tinypages/conf.py +0 -0
  38. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/tinypages/docstring_cases.py +0 -0
  39. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/tinypages/docstring_cases.rst +0 -0
  40. {sphinx_examples_as_code-0.4.0 → sphinx_examples_as_code-0.4.1}/tests/tinypages/index.rst +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sphinx-examples-as-code
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Sphinx extension for converting docstring examples into downloadable code.
5
5
  Author-email: The PyVista Developers <info@pyvista.org>
6
6
  License-Expression: MIT
@@ -120,9 +120,11 @@ What happens to the content of an Examples section:
120
120
  `.. rubric:: See Also`, or a hand-written `See Also` heading) and always renders the
121
121
  same way.
122
122
  - A bullet/numbered list becomes a `-`/`N.`-marked line per item, set off with a blank
123
- line on both sides in either format. A definition list's term stays at the surrounding
124
- indent; its definition (the body nested under it) is indented one level further in
125
- `.py`, same as an admonition's own content.
123
+ line on both sides in either format a bare `#` instead of a real blank line when
124
+ that falls inside an admonition or a definition's own body in `.py`, so the whole
125
+ thing still reads as one unbroken comment block. A definition list's term stays at
126
+ the surrounding indent; its definition (the body nested under it) is indented one
127
+ level further in `.py`, same as an admonition's own content.
126
128
  - Cross-references and inline code (`:class:`, `:meth:`, `:func:`, `:attr:`,
127
129
  double-backtick literals, ...) keep their display text, wrapped in backticks (e.g.
128
130
  ``:class:`pyvista.Plotter` `` -> `` `pyvista.Plotter` ``). If `html_baseurl` is set and
@@ -93,9 +93,11 @@ What happens to the content of an Examples section:
93
93
  `.. rubric:: See Also`, or a hand-written `See Also` heading) and always renders the
94
94
  same way.
95
95
  - A bullet/numbered list becomes a `-`/`N.`-marked line per item, set off with a blank
96
- line on both sides in either format. A definition list's term stays at the surrounding
97
- indent; its definition (the body nested under it) is indented one level further in
98
- `.py`, same as an admonition's own content.
96
+ line on both sides in either format a bare `#` instead of a real blank line when
97
+ that falls inside an admonition or a definition's own body in `.py`, so the whole
98
+ thing still reads as one unbroken comment block. A definition list's term stays at
99
+ the surrounding indent; its definition (the body nested under it) is indented one
100
+ level further in `.py`, same as an admonition's own content.
99
101
  - Cross-references and inline code (`:class:`, `:meth:`, `:func:`, `:attr:`,
100
102
  double-backtick literals, ...) keep their display text, wrapped in backticks (e.g.
101
103
  ``:class:`pyvista.Plotter` `` -> `` `pyvista.Plotter` ``). If `html_baseurl` is set and
@@ -403,6 +403,34 @@ def _indent_comment_line(line: str) -> str:
403
403
  return f'# {_ADMONITION_CONTENT_INDENT}{line.removeprefix("# ")}'
404
404
 
405
405
 
406
+ def _is_raw_code_line(line: str) -> bool:
407
+ """Check whether a rendered ``.py`` line is real code, not a ``#`` comment line."""
408
+ return bool(line) and not line.startswith('#')
409
+
410
+
411
+ def _fill_comment_gaps(lines: list[str]) -> list[str]:
412
+ """Turn a blank separator line into a bare ``#`` unless it borders raw code.
413
+
414
+ ``_join_segments`` forces a blank line around some segment boundaries
415
+ (e.g. a paragraph followed by a nested list) meant to visually separate
416
+ unrelated top-level content. Folded into one ``# LABEL:`` comment block
417
+ instead (see ``_indent_label_content``/``_definition_segment``), that
418
+ same blank line needs a ``#`` to still read as part of that one block.
419
+ A blank line bordering a raw code line (left flush and uncommented --
420
+ see ``_convert_node``'s doctest/literal-block handling) stays blank,
421
+ since that boundary really is between code and comment.
422
+ """
423
+ result: list[str] = []
424
+ for i, line in enumerate(lines):
425
+ if line != '':
426
+ result.append(line)
427
+ continue
428
+ before = lines[i - 1] if i > 0 else ''
429
+ after = lines[i + 1] if i + 1 < len(lines) else ''
430
+ result.append(line if _is_raw_code_line(before) or _is_raw_code_line(after) else '#')
431
+ return result
432
+
433
+
406
434
  def _indent_label_content(lines: list[str], fmt: str) -> list[str]:
407
435
  """Indent every line after the first (a ``# LABEL:`` line) under it.
408
436
 
@@ -410,7 +438,8 @@ def _indent_label_content(lines: list[str], fmt: str) -> list[str]:
410
438
  """
411
439
  if fmt != 'py' or not lines:
412
440
  return lines
413
- return [lines[0], *(_indent_comment_line(line) for line in lines[1:])]
441
+ label, *rest = _fill_comment_gaps(lines)
442
+ return [label, *(_indent_comment_line(line) for line in rest)]
414
443
 
415
444
 
416
445
  def _definition_segment(node: nodes.definition, ctx: _RenderContext) -> list[Segment]:
@@ -423,7 +452,7 @@ def _definition_segment(node: nodes.definition, ctx: _RenderContext) -> list[Seg
423
452
  segments.extend(_convert_node(child, ctx))
424
453
  lines = _join_segments(segments)
425
454
  if ctx.fmt == 'py':
426
- lines = [_indent_comment_line(line) for line in lines]
455
+ lines = [_indent_comment_line(line) for line in _fill_comment_gaps(lines)]
427
456
  return [('text', lines)] if lines else []
428
457
 
429
458
 
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.4.0'
22
- __version_tuple__ = version_tuple = (0, 4, 0)
21
+ __version__ = version = '0.4.1'
22
+ __version_tuple__ = version_tuple = (0, 4, 1)
23
23
 
24
- __commit_id__ = commit_id = 'ge8e70c9b9'
24
+ __commit_id__ = commit_id = 'gfbf3dad3c'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sphinx-examples-as-code
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Sphinx extension for converting docstring examples into downloadable code.
5
5
  Author-email: The PyVista Developers <info@pyvista.org>
6
6
  License-Expression: MIT
@@ -120,9 +120,11 @@ What happens to the content of an Examples section:
120
120
  `.. rubric:: See Also`, or a hand-written `See Also` heading) and always renders the
121
121
  same way.
122
122
  - A bullet/numbered list becomes a `-`/`N.`-marked line per item, set off with a blank
123
- line on both sides in either format. A definition list's term stays at the surrounding
124
- indent; its definition (the body nested under it) is indented one level further in
125
- `.py`, same as an admonition's own content.
123
+ line on both sides in either format a bare `#` instead of a real blank line when
124
+ that falls inside an admonition or a definition's own body in `.py`, so the whole
125
+ thing still reads as one unbroken comment block. A definition list's term stays at
126
+ the surrounding indent; its definition (the body nested under it) is indented one
127
+ level further in `.py`, same as an admonition's own content.
126
128
  - Cross-references and inline code (`:class:`, `:meth:`, `:func:`, `:attr:`,
127
129
  double-backtick literals, ...) keep their display text, wrapped in backticks (e.g.
128
130
  ``:class:`pyvista.Plotter` `` -> `` `pyvista.Plotter` ``). If `html_baseurl` is set and
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "0.4.0",
2
+ "tag": "0.4.1",
3
3
  "distance": 0,
4
- "node": "ge8e70c9b93c8984fd11c6144985637d91f8c59f3",
4
+ "node": "gfbf3dad3c895f46b35267a9ce9bc87e21d891625",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-08-11"
@@ -491,6 +491,68 @@ def test_indent_label_content_skips_only_the_first_line():
491
491
  assert seac._indent_label_content(['# NOTE:'], 'py') == ['# NOTE:']
492
492
 
493
493
 
494
+ def test_indent_label_content_fills_gap_between_two_comment_lines():
495
+ # a forced blank between a paragraph and a following list (see
496
+ # _join_segments) must not read as the comment block ending partway
497
+ # through
498
+ lines = ['# SEE ALSO:', '# intro', '', '# - item one']
499
+ assert seac._indent_label_content(lines, 'py') == [
500
+ '# SEE ALSO:',
501
+ '# intro',
502
+ '#',
503
+ '# - item one',
504
+ ]
505
+
506
+
507
+ def test_indent_label_content_keeps_real_blank_next_to_code():
508
+ # a blank line bordering raw, uncommented code (see
509
+ # test_convert_node_note_with_code_indents_text_not_code) stays a real
510
+ # blank line -- turning it into '#' would misrepresent it as a comment
511
+ lines = ['# NOTE:', '# intro', '', 'x = 1']
512
+ assert seac._indent_label_content(lines, 'py') == ['# NOTE:', '# intro', '', 'x = 1']
513
+
514
+
515
+ # ---------------------------------------------------------------------------
516
+ # _fill_comment_gaps
517
+ # ---------------------------------------------------------------------------
518
+
519
+
520
+ def test_fill_comment_gaps_between_comments_becomes_hash():
521
+ assert seac._fill_comment_gaps(['# a', '', '# b']) == ['# a', '#', '# b']
522
+
523
+
524
+ def test_fill_comment_gaps_next_to_code_stays_blank():
525
+ assert seac._fill_comment_gaps(['# a', '', 'x = 1']) == ['# a', '', 'x = 1']
526
+ assert seac._fill_comment_gaps(['x = 1', '', '# a']) == ['x = 1', '', '# a']
527
+
528
+
529
+ def test_fill_comment_gaps_leading_and_trailing_blank():
530
+ assert seac._fill_comment_gaps(['', '# a']) == ['#', '# a']
531
+ assert seac._fill_comment_gaps(['# a', '']) == ['# a', '#']
532
+
533
+
534
+ def test_fill_comment_gaps_no_blanks_unchanged():
535
+ lines = ['# a', '# b']
536
+ assert seac._fill_comment_gaps(lines) == lines
537
+
538
+
539
+ # ---------------------------------------------------------------------------
540
+ # _is_raw_code_line
541
+ # ---------------------------------------------------------------------------
542
+
543
+
544
+ def test_is_raw_code_line_true_for_code():
545
+ assert seac._is_raw_code_line('x = 1')
546
+
547
+
548
+ def test_is_raw_code_line_false_for_comment():
549
+ assert not seac._is_raw_code_line('# x = 1')
550
+
551
+
552
+ def test_is_raw_code_line_false_for_blank():
553
+ assert not seac._is_raw_code_line('')
554
+
555
+
494
556
  # ---------------------------------------------------------------------------
495
557
  # _definition_segment
496
558
  # ---------------------------------------------------------------------------
@@ -526,6 +588,23 @@ def test_definition_segment_empty_returns_empty():
526
588
  assert seac._convert_node(nodes.definition(), _ctx()) == []
527
589
 
528
590
 
591
+ def test_definition_segment_py_fills_gap_before_nested_list():
592
+ # a paragraph followed by a nested bullet list inside one definition --
593
+ # the forced blank line between them (see _join_segments) must not
594
+ # break the definition out of its own '#'-commented block
595
+ definition = nodes.definition()
596
+ definition += nodes.paragraph('', 'intro text')
597
+ bullet_list = nodes.bullet_list()
598
+ item = nodes.list_item()
599
+ item += nodes.paragraph('', 'first item')
600
+ bullet_list += item
601
+ definition += bullet_list
602
+
603
+ assert seac._convert_node(definition, _ctx(fmt='py')) == [
604
+ ('text', ['# intro text', '#', '# - first item'])
605
+ ]
606
+
607
+
529
608
  def test_convert_node_definition_list_item_term_not_indented_definition_is():
530
609
  # the term itself stays at the surrounding indent level -- only its
531
610
  # definition (the body nested under it) gets the extra indent
@@ -330,9 +330,10 @@ def test_seealso_structured_py(built: tuple[Path, list[Path]]):
330
330
  assert lines[term_idx + 1] == '# See this dataset in the gallery for more info.'
331
331
 
332
332
  intro_idx = lines.index('# This dataset is used in the following examples:')
333
- # the bullet list is set off with a blank line before it, each item
334
- # '- '-marked, back at the base (non-definition) indent level
335
- assert lines[intro_idx + 1] == ''
333
+ # the bullet list is set off with a bare '#' before it (not a real blank
334
+ # line -- the whole SEE ALSO body stays one unbroken comment block),
335
+ # each item '- '-marked, back at the base (non-definition) indent level
336
+ assert lines[intro_idx + 1] == '#'
336
337
  assert lines[intro_idx + 2] == '# - Some Target'
337
338
  assert lines[intro_idx + 3] == '# - Some Target'
338
339