sphinx-examples-as-code 0.3.0__tar.gz → 0.3.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 (41) hide show
  1. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/PKG-INFO +8 -6
  2. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/README.md +7 -5
  3. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/sphinx_examples_as_code/__init__.py +22 -16
  4. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/sphinx_examples_as_code/_version.py +3 -3
  5. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/sphinx_examples_as_code.egg-info/PKG-INFO +8 -6
  6. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/sphinx_examples_as_code.egg-info/SOURCES.txt +1 -0
  7. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/sphinx_examples_as_code.egg-info/scm_file_list.json +17 -16
  8. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/sphinx_examples_as_code.egg-info/scm_version.json +2 -2
  9. sphinx_examples_as_code-0.3.1/tests/heading_level_fixture/examples/plot_three_levels.py +19 -0
  10. sphinx_examples_as_code-0.3.1/tests/test_heading_level_reuse.py +81 -0
  11. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/test_sphinx_examples_as_code.py +38 -2
  12. sphinx_examples_as_code-0.3.0/tests/test_heading_level_reuse.py +0 -41
  13. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/.github/dependabot.yml +0 -0
  14. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/.github/release.yml +0 -0
  15. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/.github/workflows/ci.yml +0 -0
  16. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/.gitignore +0 -0
  17. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/.pre-commit-config.yaml +0 -0
  18. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/LICENSE +0 -0
  19. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/pyproject.toml +0 -0
  20. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/setup.cfg +0 -0
  21. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/sphinx_examples_as_code.egg-info/dependency_links.txt +0 -0
  22. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/sphinx_examples_as_code.egg-info/requires.txt +0 -0
  23. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/sphinx_examples_as_code.egg-info/top_level.txt +0 -0
  24. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/gallery_fixture/conf.py +0 -0
  25. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/gallery_fixture/examples/GALLERY_HEADER.rst +0 -0
  26. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/gallery_fixture/examples/plot_minimal.py +0 -0
  27. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/gallery_fixture/index.rst +0 -0
  28. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/heading_level_fixture/conf.py +0 -0
  29. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/heading_level_fixture/examples/GALLERY_HEADER.rst +0 -0
  30. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/heading_level_fixture/examples/plot_reused_level.py +0 -0
  31. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/heading_level_fixture/index.rst +0 -0
  32. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/single_function_fixture/conf.py +0 -0
  33. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/single_function_fixture/index.rst +0 -0
  34. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/single_function_fixture/mymodule.py +0 -0
  35. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/test_gallery_downloads.py +0 -0
  36. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/test_single_function_page.py +0 -0
  37. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/test_tinypages.py +0 -0
  38. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/tinypages/conf.py +0 -0
  39. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/tinypages/docstring_cases.py +0 -0
  40. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.1}/tests/tinypages/docstring_cases.rst +0 -0
  41. {sphinx_examples_as_code-0.3.0 → sphinx_examples_as_code-0.3.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.3.0
3
+ Version: 0.3.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
@@ -155,11 +155,13 @@ is left completely untouched. Gallery pages and ordinary docstring/prose pages (
155
155
  the Examples-section behavior above) can coexist on the same site.
156
156
 
157
157
  A `# %%` cell with its own RST heading gets the same title-plus-underline treatment as
158
- the file's own header, and renders as a real Markdown heading in `.ipynb` (`<h1>` for the
159
- file's own header, `# Title` + `# ====`; `<h2>` for a cell heading, `# Title` + `# ----`).
160
- A cell heading nested under the page's own title (the common case) is level 2; one that
161
- reuses the page title's own underline character -- a real RST heading, one level up --
162
- is level 1, matching the file's own header.
158
+ the file's own header, and renders as a real Markdown heading in `.ipynb`. Level is
159
+ relative to actual RST section nesting, not always one below the file's own header:
160
+ level 1 (`<h1>`, `# Title` + `# ====`) for the file's own header, or a cell heading that
161
+ reuses the page title's own underline character; level 2 (`<h2>`, `# Title` + `# ----`)
162
+ for a cell heading nested under it (the common case), or one level below whatever
163
+ heading precedes it. Level 3 and deeper use ATX syntax instead (`# ### Title`), since
164
+ Markdown's underline-style headings only support two levels.
163
165
 
164
166
  Two things worth knowing before turning this on:
165
167
 
@@ -128,11 +128,13 @@ is left completely untouched. Gallery pages and ordinary docstring/prose pages (
128
128
  the Examples-section behavior above) can coexist on the same site.
129
129
 
130
130
  A `# %%` cell with its own RST heading gets the same title-plus-underline treatment as
131
- the file's own header, and renders as a real Markdown heading in `.ipynb` (`<h1>` for the
132
- file's own header, `# Title` + `# ====`; `<h2>` for a cell heading, `# Title` + `# ----`).
133
- A cell heading nested under the page's own title (the common case) is level 2; one that
134
- reuses the page title's own underline character -- a real RST heading, one level up --
135
- is level 1, matching the file's own header.
131
+ the file's own header, and renders as a real Markdown heading in `.ipynb`. Level is
132
+ relative to actual RST section nesting, not always one below the file's own header:
133
+ level 1 (`<h1>`, `# Title` + `# ====`) for the file's own header, or a cell heading that
134
+ reuses the page title's own underline character; level 2 (`<h2>`, `# Title` + `# ----`)
135
+ for a cell heading nested under it (the common case), or one level below whatever
136
+ heading precedes it. Level 3 and deeper use ATX syntax instead (`# ### Title`), since
137
+ Markdown's underline-style headings only support two levels.
136
138
 
137
139
  Two things worth knowing before turning this on:
138
140
 
@@ -368,23 +368,29 @@ def _convert_literal_block(node: nodes.literal_block) -> list[Segment]:
368
368
  return [('directive', comment_lines)]
369
369
 
370
370
 
371
- #: Setext underline character per heading level -- ``=`` for the file's own
372
- #: top-level header (level 1), ``-`` for a subheading (level 2). CommonMark's
373
- #: setext syntax only supports these two levels.
371
+ #: Setext underline character for the two levels it supports -- ``=`` for
372
+ #: the file's own top-level header (level 1), ``-`` for a subheading
373
+ #: (level 2). Anything deeper uses ATX ``#`` syntax instead (see
374
+ #: ``_title_underline_segment``).
374
375
  _TITLE_UNDERLINE_CHARS = {1: '=', 2: '-'}
375
376
 
376
377
 
377
378
  def _title_underline_segment(title: str, level: int = 1) -> Segment:
378
- """Build a title + underline directive segment, e.g. ``# Title`` + ``# =====``.
379
-
380
- Shared by the file's own header (see ``_header_segment``), which is
381
- always level 1, and gallery mode's sibling-section headings, which are
382
- level 2. The underline is what makes this render as a real Markdown
383
- heading in ``.ipynb`` (setext-style, once the ``#`` comment prefix is
384
- stripped for markdown cells) rather than plain text.
379
+ """Build a heading directive segment for ``title`` at the given level.
380
+
381
+ Levels 1 and 2 use a setext-style title + underline (e.g. ``# Title`` +
382
+ ``# =====``), matching the file's own header (see ``_header_segment``)
383
+ and gallery mode's sibling-section headings respectively. Level 3+ uses
384
+ ATX ``#`` syntax instead (e.g. ``# ### Title``), since CommonMark's
385
+ setext syntax only supports the first two levels. Either way, this is
386
+ what makes the heading render as real Markdown in ``.ipynb`` (once the
387
+ ``#`` comment prefix is stripped for markdown cells) rather than plain
388
+ text.
385
389
  """
386
- underline = _TITLE_UNDERLINE_CHARS[level] * len(title)
387
- return ('directive', [f'# {title}', f'# {underline}'])
390
+ if level <= 2:
391
+ underline = _TITLE_UNDERLINE_CHARS[level] * len(title)
392
+ return ('directive', [f'# {title}', f'# {underline}'])
393
+ return ('directive', [f'# {"#" * level} {title}'])
388
394
 
389
395
 
390
396
  def _heading_level(title: nodes.title) -> int:
@@ -392,16 +398,16 @@ def _heading_level(title: nodes.title) -> int:
392
398
 
393
399
  Counts the title's own section and each ancestor ``nodes.section``.
394
400
  Running this on the file's own header would give level 1; a title
395
- nested inside that comes out level 2, and so does anything nested
396
- deeper (clamped -- the deepest level CommonMark's setext syntax can
397
- represent).
401
+ nested inside that comes out level 2, one nested inside that comes out
402
+ level 3, and so on -- clamped to 6, the deepest level CommonMark's ATX
403
+ heading syntax can represent.
398
404
  """
399
405
  level = 0
400
406
  node: nodes.Node | None = title.parent
401
407
  while isinstance(node, nodes.section):
402
408
  level += 1
403
409
  node = node.parent
404
- return min(level, 2)
410
+ return min(level, 6)
405
411
 
406
412
 
407
413
  def _convert_admonition(
@@ -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.3.0'
22
- __version_tuple__ = version_tuple = (0, 3, 0)
21
+ __version__ = version = '0.3.1'
22
+ __version_tuple__ = version_tuple = (0, 3, 1)
23
23
 
24
- __commit_id__ = commit_id = 'g3c1ab701a'
24
+ __commit_id__ = commit_id = 'g6bae5922a'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sphinx-examples-as-code
3
- Version: 0.3.0
3
+ Version: 0.3.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
@@ -155,11 +155,13 @@ is left completely untouched. Gallery pages and ordinary docstring/prose pages (
155
155
  the Examples-section behavior above) can coexist on the same site.
156
156
 
157
157
  A `# %%` cell with its own RST heading gets the same title-plus-underline treatment as
158
- the file's own header, and renders as a real Markdown heading in `.ipynb` (`<h1>` for the
159
- file's own header, `# Title` + `# ====`; `<h2>` for a cell heading, `# Title` + `# ----`).
160
- A cell heading nested under the page's own title (the common case) is level 2; one that
161
- reuses the page title's own underline character -- a real RST heading, one level up --
162
- is level 1, matching the file's own header.
158
+ the file's own header, and renders as a real Markdown heading in `.ipynb`. Level is
159
+ relative to actual RST section nesting, not always one below the file's own header:
160
+ level 1 (`<h1>`, `# Title` + `# ====`) for the file's own header, or a cell heading that
161
+ reuses the page title's own underline character; level 2 (`<h2>`, `# Title` + `# ----`)
162
+ for a cell heading nested under it (the common case), or one level below whatever
163
+ heading precedes it. Level 3 and deeper use ATX syntax instead (`# ### Title`), since
164
+ Markdown's underline-style headings only support two levels.
163
165
 
164
166
  Two things worth knowing before turning this on:
165
167
 
@@ -28,6 +28,7 @@ tests/heading_level_fixture/conf.py
28
28
  tests/heading_level_fixture/index.rst
29
29
  tests/heading_level_fixture/examples/GALLERY_HEADER.rst
30
30
  tests/heading_level_fixture/examples/plot_reused_level.py
31
+ tests/heading_level_fixture/examples/plot_three_levels.py
31
32
  tests/single_function_fixture/conf.py
32
33
  tests/single_function_fixture/index.rst
33
34
  tests/single_function_fixture/mymodule.py
@@ -1,33 +1,34 @@
1
1
  {
2
2
  "files": [
3
+ ".pre-commit-config.yaml",
4
+ "pyproject.toml",
3
5
  "LICENSE",
4
6
  "README.md",
5
- ".pre-commit-config.yaml",
6
7
  ".gitignore",
7
- "pyproject.toml",
8
8
  ".github/dependabot.yml",
9
9
  ".github/release.yml",
10
10
  ".github/workflows/ci.yml",
11
- "sphinx_examples_as_code/__init__.py",
12
- "tests/test_sphinx_examples_as_code.py",
13
- "tests/test_single_function_page.py",
14
11
  "tests/test_tinypages.py",
15
- "tests/test_gallery_downloads.py",
12
+ "tests/test_single_function_page.py",
16
13
  "tests/test_heading_level_reuse.py",
17
- "tests/gallery_fixture/conf.py",
18
- "tests/gallery_fixture/index.rst",
19
- "tests/gallery_fixture/examples/GALLERY_HEADER.rst",
20
- "tests/gallery_fixture/examples/plot_minimal.py",
21
- "tests/heading_level_fixture/conf.py",
14
+ "tests/test_gallery_downloads.py",
15
+ "tests/test_sphinx_examples_as_code.py",
22
16
  "tests/heading_level_fixture/index.rst",
17
+ "tests/heading_level_fixture/conf.py",
23
18
  "tests/heading_level_fixture/examples/plot_reused_level.py",
19
+ "tests/heading_level_fixture/examples/plot_three_levels.py",
24
20
  "tests/heading_level_fixture/examples/GALLERY_HEADER.rst",
25
- "tests/single_function_fixture/mymodule.py",
26
- "tests/single_function_fixture/conf.py",
27
- "tests/single_function_fixture/index.rst",
28
- "tests/tinypages/docstring_cases.py",
21
+ "tests/tinypages/index.rst",
29
22
  "tests/tinypages/conf.py",
23
+ "tests/tinypages/docstring_cases.py",
30
24
  "tests/tinypages/docstring_cases.rst",
31
- "tests/tinypages/index.rst"
25
+ "tests/gallery_fixture/index.rst",
26
+ "tests/gallery_fixture/conf.py",
27
+ "tests/gallery_fixture/examples/plot_minimal.py",
28
+ "tests/gallery_fixture/examples/GALLERY_HEADER.rst",
29
+ "tests/single_function_fixture/index.rst",
30
+ "tests/single_function_fixture/conf.py",
31
+ "tests/single_function_fixture/mymodule.py",
32
+ "sphinx_examples_as_code/__init__.py"
32
33
  ]
33
34
  }
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "0.3.0",
2
+ "tag": "0.3.1",
3
3
  "distance": 0,
4
- "node": "g3c1ab701a7525c5768d4a1f0ef5090d5db4f4887",
4
+ "node": "g6bae5922a337380c3e8f439cfea8c645d1d11342",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-08-07"
@@ -0,0 +1,19 @@
1
+ """Three level example
2
+ ===================
3
+
4
+ Intro text.
5
+ """
6
+
7
+ # %%
8
+ # Section
9
+ # -------
10
+
11
+ from __future__ import annotations
12
+
13
+ x = 1
14
+
15
+ # %%
16
+ # Subsection
17
+ # """"""""""
18
+
19
+ y = 2
@@ -0,0 +1,81 @@
1
+ """Real-build regression tests for gallery sibling-section heading levels.
2
+
3
+ Builds a real sphinx-gallery site (not a hand-built doctree) covering:
4
+ one sibling-section heading nested under the page's own title (the common
5
+ case), one reusing the page title's own underline character (a real RST
6
+ heading, one level up from the first), and three genuinely nested levels
7
+ (page title, section, subsection). Complements the hand-built-doctree unit
8
+ tests for ``_heading_level``/``_title_underline_segment`` in
9
+ ``test_sphinx_examples_as_code.py``.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ from pathlib import Path
16
+ import shutil
17
+
18
+ import pytest
19
+ from test_gallery_downloads import _is_ours
20
+ from test_tinypages import _run_sphinx_build
21
+ from test_tinypages import _sphinx_build_cmd
22
+
23
+ FIXTURE_DIR = Path(__file__).parent / 'heading_level_fixture'
24
+
25
+
26
+ @pytest.fixture(scope='module')
27
+ def built(tmp_path_factory) -> Path:
28
+ # Copy the fixture rather than building from it in place: sphinx-gallery
29
+ # writes its generated .rst files into the source tree itself as a side
30
+ # effect of building (see test_gallery_downloads.py's own _build()).
31
+ tmp_path = tmp_path_factory.mktemp('heading_level_build')
32
+ src_dir = tmp_path / 'src'
33
+ shutil.copytree(FIXTURE_DIR, src_dir)
34
+
35
+ html_dir = tmp_path / 'html'
36
+ doctree_dir = tmp_path / 'doctrees'
37
+ returncode, out, err = _run_sphinx_build(_sphinx_build_cmd(src_dir, html_dir, doctree_dir))
38
+ assert returncode == 0, f'sphinx build failed with stdout:\n{out}\nstderr:\n{err}\n'
39
+ return html_dir
40
+
41
+
42
+ def _generated(html_dir: Path, name: str) -> Path:
43
+ # gallery_downloads=True leaves sphinx-gallery's own same-named download
44
+ # in place too (see test_gallery_downloads.py) -- _is_ours picks ours out.
45
+ matches = [p for p in (html_dir / '_downloads').rglob(name) if _is_ours(p)]
46
+ assert len(matches) == 1, f'expected exactly one generated {name}, got {matches}'
47
+ return matches[0]
48
+
49
+
50
+ def test_reused_underline_char_renders_as_level_1(built: Path):
51
+ py_path = _generated(built, 'plot_reused_level.py')
52
+ lines = py_path.read_text(encoding='utf-8').splitlines()
53
+
54
+ nested_idx = lines.index('# Nested Subsection')
55
+ assert lines[nested_idx + 1] == '# ' + '-' * len('Nested Subsection')
56
+
57
+ reused_idx = lines.index('# Reused Top Level')
58
+ assert lines[reused_idx + 1] == '# ' + '=' * len('Reused Top Level')
59
+
60
+
61
+ def test_three_genuine_levels_uses_atx_for_the_third(built: Path):
62
+ """A subsection nested two sections deep gets ATX ``###``, not another dash line.
63
+
64
+ Otherwise it would render identically to its own parent section's
65
+ heading -- indistinguishable from a sibling instead of a subsection.
66
+ """
67
+ py_path = _generated(built, 'plot_three_levels.py')
68
+ lines = py_path.read_text(encoding='utf-8').splitlines()
69
+
70
+ section_idx = lines.index('# Section')
71
+ assert lines[section_idx + 1] == '# ' + '-' * len('Section')
72
+
73
+ assert '# ### Subsection' in lines
74
+ assert '# Subsection' not in lines # not a level-2 dash heading
75
+
76
+
77
+ def test_three_genuine_levels_atx_renders_as_h3_in_ipynb(built: Path):
78
+ nb_path = _generated(built, 'plot_three_levels.ipynb')
79
+ notebook = json.loads(nb_path.read_text(encoding='utf-8'))
80
+ all_source = ''.join(''.join(cell['source']) for cell in notebook['cells'])
81
+ assert '### Subsection' in all_source
@@ -771,6 +771,18 @@ def test_title_underline_segment_level_2_uses_dashes():
771
771
  assert lines == ['# A Title', '# -------']
772
772
 
773
773
 
774
+ def test_title_underline_segment_level_3_uses_atx():
775
+ kind, lines = seac._title_underline_segment('A Title', level=3)
776
+ assert kind == 'directive'
777
+ assert lines == ['# ### A Title']
778
+
779
+
780
+ def test_title_underline_segment_level_6_uses_atx():
781
+ kind, lines = seac._title_underline_segment('A Title', level=6)
782
+ assert kind == 'directive'
783
+ assert lines == ['# ###### A Title']
784
+
785
+
774
786
  # ---------------------------------------------------------------------------
775
787
  # _heading_level
776
788
  # ---------------------------------------------------------------------------
@@ -785,7 +797,7 @@ def test_heading_level_one_section_deep_is_level_2():
785
797
  assert seac._heading_level(title) == 2
786
798
 
787
799
 
788
- def test_heading_level_two_sections_deep_is_clamped_to_2():
800
+ def test_heading_level_two_sections_deep_is_3():
789
801
  page_section = nodes.section()
790
802
  section = nodes.section()
791
803
  subsection = nodes.section()
@@ -793,7 +805,18 @@ def test_heading_level_two_sections_deep_is_clamped_to_2():
793
805
  subsection += title
794
806
  section += subsection
795
807
  page_section += section
796
- assert seac._heading_level(title) == 2
808
+ assert seac._heading_level(title) == 3
809
+
810
+
811
+ def test_heading_level_clamped_to_6():
812
+ current = nodes.section()
813
+ for _ in range(8):
814
+ nested = nodes.section()
815
+ current += nested
816
+ current = nested
817
+ title = nodes.title('', 'Very deeply nested')
818
+ current += title
819
+ assert seac._heading_level(title) == 6
797
820
 
798
821
 
799
822
  def test_heading_level_not_nested_under_anything_is_level_1():
@@ -840,6 +863,19 @@ def test_convert_node_title_not_nested_uses_level_1():
840
863
  ]
841
864
 
842
865
 
866
+ def test_convert_node_title_two_sections_deep_uses_atx():
867
+ # e.g. a "# %%" cell's own heading nested inside another sibling
868
+ # section's heading, rather than directly under the page's own title
869
+ page_section = nodes.section()
870
+ section = nodes.section()
871
+ subsection = nodes.section()
872
+ title = nodes.title('', 'A sub-subsection')
873
+ subsection += title
874
+ section += subsection
875
+ page_section += section
876
+ assert seac._convert_node(title, _ctx()) == [('directive', ['# ### A sub-subsection'])]
877
+
878
+
843
879
  def test_convert_node_empty_title_returns_empty():
844
880
  assert seac._convert_node(nodes.title(), _ctx()) == []
845
881
 
@@ -1,41 +0,0 @@
1
- """Real-build regression test for gallery sibling-section heading levels.
2
-
3
- Builds a real sphinx-gallery site (not a hand-built doctree) with two
4
- sibling-section headings: one nested under the page's own title (the
5
- common case), one reusing the page title's own underline character (a
6
- real RST heading, one level up from the first). Complements the
7
- hand-built-doctree unit tests for ``_heading_level`` in
8
- ``test_sphinx_examples_as_code.py``.
9
- """
10
-
11
- from __future__ import annotations
12
-
13
- from pathlib import Path
14
- import shutil
15
-
16
- from test_tinypages import _run_sphinx_build
17
- from test_tinypages import _sphinx_build_cmd
18
-
19
- FIXTURE_DIR = Path(__file__).parent / 'heading_level_fixture'
20
-
21
-
22
- def test_reused_underline_char_renders_as_level_1(tmp_path: Path):
23
- # Copy the fixture rather than building from it in place: sphinx-gallery
24
- # writes its generated .rst files into the source tree itself as a side
25
- # effect of building (see test_gallery_downloads.py's own _build()).
26
- src_dir = tmp_path / 'src'
27
- shutil.copytree(FIXTURE_DIR, src_dir)
28
-
29
- html_dir = tmp_path / 'html'
30
- doctree_dir = tmp_path / 'doctrees'
31
- returncode, out, err = _run_sphinx_build(_sphinx_build_cmd(src_dir, html_dir, doctree_dir))
32
- assert returncode == 0, f'sphinx build failed with stdout:\n{out}\nstderr:\n{err}\n'
33
-
34
- py_path = next((html_dir / '_downloads').rglob('plot_reused_level.py'))
35
- lines = py_path.read_text(encoding='utf-8').splitlines()
36
-
37
- nested_idx = lines.index('# Nested Subsection')
38
- assert lines[nested_idx + 1] == '# ' + '-' * len('Nested Subsection')
39
-
40
- reused_idx = lines.index('# Reused Top Level')
41
- assert lines[reused_idx + 1] == '# ' + '=' * len('Reused Top Level')