Skip to content

Commit 6e433e7

Browse files
committed
Merge main into update-languages
Resolved merge conflicts in: - sphinx_exercise/directive.py: Accepted alphabetically sorted imports from main - sphinx_exercise/nodes.py: Removed extra blank line This merge brings in all the test suite modernization from main including: - Python 3.11-3.13 and Sphinx 6-8 compatibility - Complete pathlib migration (os.path -> pathlib.Path) - Image hash normalization for cross-platform tests - All test fixtures for Sphinx 6, 7, and 8
2 parents 135dafe + 4b49053 commit 6e433e7

File tree

153 files changed

+2531
-70
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

153 files changed

+2531
-70
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ jobs:
2323
runs-on: ubuntu-latest
2424
strategy:
2525
matrix:
26-
python-version: ["3.11", "3.12"]
26+
python-version: ["3.11", "3.12", "3.13"]
27+
sphinx-version: ["6", "7", "8"]
2728
steps:
2829
- uses: actions/checkout@v4
2930
- name: Set up Python ${{ matrix.python-version }}
@@ -34,16 +35,17 @@ jobs:
3435
run : |
3536
python -m pip install --upgrade pip
3637
pip install -e.[testing]
38+
pip install "sphinx>=${{ matrix.sphinx-version }},<${{ matrix.sphinx-version == '6' && '7' || matrix.sphinx-version == '7' && '8' || '9' }}"
3739
- name: Run pytest
3840
run: |
3941
pytest --durations=10 --cov=sphinx_exercise --cov-report=xml --cov-report=term-missing
4042
- name: Create cov
4143
run: coverage xml
4244
- name: Upload to Codecov
43-
if: false && (matrix.python-version == '3.11')
45+
if: false && (matrix.python-version == '3.11' && matrix.sphinx-version == '8')
4446
uses: codecov/codecov-action@v4
4547
with:
46-
name: sphinx-exercise-pytest-py3.11
48+
name: sphinx-exercise-pytest-py3.11-sphinx8
4749
token: "${{ secrets.CODECOV_TOKEN }}"
4850
flags: pytests
4951
file: ./coverage.xml

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,25 @@
2727

2828
_No changelog available for this version._
2929

30+
## [v1.0.1](https://github.com/executablebooks/sphinx-exercise/tree/v1.0.1) (2024-07-01)
31+
32+
### Improved 👌
33+
34+
- Updates to testing infrastructure and minor bug fixes
35+
- Fixed JupyterBuilder handling in test suite
36+
37+
## [v1.0.0](https://github.com/executablebooks/sphinx-exercise/tree/v1.0.0) (2024-01-15)
38+
39+
### Improved 👌
40+
41+
- Added support for Sphinx 7
42+
- Updated build and CI infrastructure
43+
- Fixed deprecation warnings for Sphinx 7 compatibility
44+
- Improved type hints throughout codebase
45+
- Fixed doctree node mutation issues by copying nodes
46+
- Updated codecov to version 3
47+
- Pinned matplotlib to 3.7.* for testing stability
48+
3049
## [v0.4.1](https://github.com/executablebooks/sphinx-exercise/tree/v0.4.1) (2023-1-23)
3150

3251
### Improved 👌

pyproject.toml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ dynamic = ["version"]
88
description = "A Sphinx extension for producing exercises and solutions."
99
readme = "README.md"
1010
license = { file = "LICENSE" }
11-
requires-python = ">=3.9"
11+
requires-python = ">=3.11"
1212
authors = [
1313
{ name = "QuantEcon", email = "[email protected]" },
1414
]
@@ -22,10 +22,9 @@ classifiers = [
2222
"Natural Language :: English",
2323
"Operating System :: OS Independent",
2424
"Programming Language :: Python",
25-
"Programming Language :: Python :: 3.9",
26-
"Programming Language :: Python :: 3.10",
2725
"Programming Language :: Python :: 3.11",
2826
"Programming Language :: Python :: 3.12",
27+
"Programming Language :: Python :: 3.13",
2928
"Topic :: Documentation",
3029
"Topic :: Documentation :: Sphinx",
3130
"Topic :: Software Development :: Documentation",
@@ -34,7 +33,7 @@ classifiers = [
3433
]
3534
dependencies = [
3635
"sphinx-book-theme",
37-
"sphinx>=5",
36+
"sphinx>=6.1",
3837
]
3938

4039
[project.optional-dependencies]
@@ -49,20 +48,20 @@ code_style = [
4948
"pre-commit",
5049
]
5150
rtd = [
52-
"myst-nb~=1.0.0",
51+
"myst-nb>=1.1.0",
5352
"sphinx-book-theme",
5453
"sphinx_togglebutton",
55-
"sphinx>=5,<8",
54+
"sphinx>=6.1,<9",
5655
]
5756
testing = [
5857
"beautifulsoup4",
5958
"coverage",
60-
"matplotlib==3.8.*",
61-
"myst-nb~=1.0.0",
59+
"matplotlib>=3.8",
60+
"myst-nb>=1.1.0",
6261
"pytest-cov",
6362
"pytest-regressions",
64-
"pytest~=8.0.0",
65-
"sphinx>=5,<8",
63+
"pytest>=8.0",
64+
"sphinx>=6.1,<9",
6665
"texsoup",
6766
"defusedxml", # Required by sphinx-testing
6867
]

sphinx_exercise/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
__version__ = "1.0.1"
1111

12-
import os
1312
from pathlib import Path
1413
from typing import Any, Dict, Set, Union, cast
1514
from sphinx.config import Config
@@ -215,9 +214,9 @@ def setup(app: Sphinx) -> Dict[str, Any]:
215214
app.add_css_file("exercise.css")
216215

217216
# add translations
218-
package_dir = os.path.abspath(os.path.dirname(__file__))
219-
locale_dir = os.path.join(package_dir, "translations", "locales")
220-
app.add_message_catalog(MESSAGE_CATALOG_NAME, locale_dir)
217+
package_dir = Path(__file__).parent.resolve()
218+
locale_dir = package_dir / "translations" / "locales"
219+
app.add_message_catalog(MESSAGE_CATALOG_NAME, str(locale_dir))
221220

222221
return {
223222
"version": "builtin",

sphinx_exercise/directive.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,25 @@
88
:licences: see LICENSE for details
99
"""
1010

11+
from pathlib import Path
1112
from typing import List
12-
from docutils.nodes import Node
13+
1314
from docutils import nodes
15+
from docutils.nodes import Node
1416
from docutils.parsers.rst import directives
15-
from sphinx.util.docutils import SphinxDirective
16-
from sphinx.util import logging
1717
from sphinx.locale import get_translation
18+
from sphinx.util import logging
19+
from sphinx.util.docutils import SphinxDirective
1820

1921
from .nodes import (
20-
exercise_node,
21-
exercise_enumerable_node,
2222
exercise_end_node,
23+
exercise_enumerable_node,
24+
exercise_node,
25+
exercise_subtitle,
26+
exercise_title,
27+
solution_end_node,
2328
solution_node,
2429
solution_start_node,
25-
solution_end_node,
26-
exercise_title,
27-
exercise_subtitle,
2830
solution_title,
2931
)
3032

@@ -40,7 +42,7 @@ def duplicate_labels(self, label):
4042

4143
if not label == "" and label in self.env.sphinx_exercise_registry.keys():
4244
docpath = self.env.doc2path(self.env.docname)
43-
path = docpath[: docpath.rfind(".")]
45+
path = str(Path(docpath).with_suffix(""))
4446
other_path = self.env.doc2path(
4547
self.env.sphinx_exercise_registry[label]["docname"]
4648
)

sphinx_exercise/post_transforms.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from pathlib import Path
2+
13
import sphinx.addnodes as sphinx_nodes
24
from sphinx.transforms.post_transforms import SphinxPostTransform
35
from sphinx.util import logging
@@ -195,7 +197,7 @@ def run(self):
195197
except AttributeError:
196198
docname = self.env.docname # for builder such as JupyterBuilder that don't support current_docname
197199
docpath = self.env.doc2path(docname)
198-
path = docpath[: docpath.rfind(".")]
200+
path = str(Path(docpath).with_suffix(""))
199201
msg = f"undefined label: {target_label}"
200202
logger.warning(msg, location=path, color="red")
201203
return

sphinx_exercise/translations/_convert.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import json
2-
import os
32
from pathlib import Path
43
import subprocess
54

@@ -54,9 +53,9 @@ def convert_json(folder=None):
5453
subprocess.check_call(
5554
[
5655
"msgfmt",
57-
os.path.abspath(path),
56+
str(path.resolve()),
5857
"-o",
59-
os.path.abspath(path.parent / f"{MESSAGE_CATALOG_NAME}.mo"),
58+
str((path.parent / f"{MESSAGE_CATALOG_NAME}.mo").resolve()),
6059
]
6160
)
6261

tests/books/test-gateddirective/solution-exercise-gated.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ axs[0].set_xlabel('time')
4242
axs[0].set_ylabel('s1 and s2')
4343
axs[0].grid(True)
4444
45-
cxy, f = axs[1].cohere(s1, s2, 256, 1. / dt)
45+
cxy, f = axs[1].cohere(s1, s2, NFFT=256, Fs=1. / dt)
4646
axs[1].set_ylabel('coherence')
4747
4848
fig.tight_layout()
@@ -87,7 +87,7 @@ axs[0].set_xlabel('time')
8787
axs[0].set_ylabel('s1 and s2')
8888
axs[0].grid(True)
8989
90-
cxy, f = axs[1].cohere(s1, s2, 256, 1. / dt)
90+
cxy, f = axs[1].cohere(s1, s2, NFFT=256, Fs=1. / dt)
9191
axs[1].set_ylabel('coherence')
9292
9393
fig.tight_layout()

tests/books/test-gateddirective/solution-exercise.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ axs[0].set_xlabel('time')
4242
axs[0].set_ylabel('s1 and s2')
4343
axs[0].grid(True)
4444
45-
cxy, f = axs[1].cohere(s1, s2, 256, 1. / dt)
45+
cxy, f = axs[1].cohere(s1, s2, NFFT=256, Fs=1. / dt)
4646
axs[1].set_ylabel('coherence')
4747
4848
fig.tight_layout()
@@ -85,7 +85,7 @@ axs[0].set_xlabel('time')
8585
axs[0].set_ylabel('s1 and s2')
8686
axs[0].grid(True)
8787
88-
cxy, f = axs[1].cohere(s1, s2, 256, 1. / dt)
88+
cxy, f = axs[1].cohere(s1, s2, NFFT=256, Fs=1. / dt)
8989
axs[1].set_ylabel('coherence')
9090
9191
fig.tight_layout()

tests/conftest.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
def rootdir(tmpdir):
1616
from sphinx.testing.path import path
1717

18-
src = path(__file__).parent.absolute() / "books"
18+
# In Sphinx 6, path objects don't have .absolute() method, but they are already absolute
19+
src = path(__file__).parent / "books"
1920
dst = tmpdir.join("books")
2021
shutil.copytree(src, dst)
2122
yield path(dst)
@@ -94,6 +95,10 @@ class FileRegression:
9495
(r"original_uri=\"[^\"]*\"\s", ""),
9596
# TODO: Remove when support for Sphinx<7.2 is dropped
9697
("Link to", "Permalink to"),
98+
# Strip ipykernel process IDs (temporary directory paths)
99+
(r"ipykernel_\d+", "ipykernel_XXXXX"),
100+
# Normalize matplotlib image hashes (platform/version dependent)
101+
(r"[a-f0-9]{64}\.png", "IMAGEHASH.png"),
97102
)
98103

99104
def __init__(self, file_regression):

0 commit comments

Comments
 (0)