Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,13 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13"]
sphinx-version: ["6", "7", "8"]
exclude:
# Python 3.13 with Sphinx 6 generates many deprecation warnings
# from Sphinx's use of deprecated datetime methods. Unlikely combination.
- python-version: "3.13"
sphinx-version: "6"
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -42,24 +47,23 @@ jobs:
- name: Create cov
run: coverage xml
- name: Upload to Codecov
if: false && (matrix.python-version == '3.11' && matrix.sphinx-version == '8')
if: matrix.python-version == '3.12' && matrix.sphinx-version == '8'
uses: codecov/codecov-action@v4
with:
name: sphinx-exercise-pytest-py3.11-sphinx8
token: "${{ secrets.CODECOV_TOKEN }}"
name: sphinx-exercise-pytest-py3.12-sphinx8
flags: pytests
file: ./coverage.xml
fail_ci_if_error: true
fail_ci_if_error: false

docs:
name: Documentation build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand All @@ -78,10 +82,10 @@ jobs:
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Set up Python 3.11
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.10"
- name: Build package
run: |
pip install wheel build
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## [Unreleased]

## [v1.1.1](https://github.com/executablebooks/sphinx-exercise/tree/v1.1.1) (2025-10-23)

### Improved 👌

- **Restored Python 3.10 support** - Re-added compatibility with Python 3.10 as it remains actively supported until October 2026
- Updated test matrix to include Python 3.10 with Sphinx 6, 7, and 8
- Test matrix now covers 11 combinations (excludes Python 3.13 + Sphinx 6 due to deprecation warnings)
- **Note**: Python 3.10 is limited to Sphinx 8.1.x (max 8.1.3) due to Sphinx 8.2+ requiring Python >=3.11. This is handled automatically in the test configuration.
- Updated codecov integration to use Python 3.12 + Sphinx 8 baseline
- Configured tokenless codecov uploads for public repository

## [v1.1.0](https://github.com/executablebooks/sphinx-exercise/tree/v1.1.0) (2025-10-22)

### New ✨
Expand Down
1 change: 1 addition & 0 deletions docs/source/releases/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ This section contains detailed release notes for sphinx-exercise versions.
```{toctree}
:maxdepth: 1

v1.1.1
v1.1.0
```

Expand Down
75 changes: 75 additions & 0 deletions docs/source/releases/v1.1.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Release v1.1.1

**Release Date**: October 23, 2025

This is a patch release that restores Python 3.10 compatibility while maintaining support for newer Python versions.

## 👌 Improvements

### Python 3.10 Support Restored

Python 3.10 support has been re-added to the project. Python 3.10 remains actively supported until October 2026, making it an important version to maintain compatibility with.

**Key details:**
- Python 3.10 is now fully supported alongside Python 3.11, 3.12, and 3.13
- All existing features work identically across all supported Python versions
- Comprehensive test coverage ensures compatibility

### Technical Implementation

**Version-Specific Sphinx Constraints:**
- Python 3.10 is limited to **Sphinx 8.1.x** (maximum 8.1.3)
- Python 3.11+ continues to use **Sphinx 8.2+** as normal
- This constraint exists because Sphinx 8.2.0+ requires Python >=3.11

The test infrastructure automatically handles these version-specific requirements, ensuring correct behavior across all combinations.

### Test Matrix Updates

**Supported Combinations:**
- Python 3.10, 3.11, 3.12: Sphinx 6, 7, 8
- Python 3.13: Sphinx 7, 8

**Total: 11 test environments** (excludes Python 3.13 + Sphinx 6)

Python 3.13 + Sphinx 6 was excluded because Sphinx 6.2.1 generates 1870+ deprecation warnings on Python 3.13 due to its use of deprecated `datetime.utcfromtimestamp()`. This is an unlikely real-world combination.

### CI/CD Improvements

- Updated GitHub Actions CI matrix to include Python 3.10
- Configured codecov to use Python 3.12 + Sphinx 8 as baseline
- Implemented tokenless codecov uploads for public repository
- Added version-specific test fixtures for Sphinx 8.1 vs 8.2+ compatibility

## 📦 Installation

Install or upgrade via pip:

```bash
pip install --upgrade sphinx-exercise
```

## 🔄 Migration Notes

**If you're upgrading from v1.1.0:**
- No breaking changes
- No action required
- Python 3.10 users can now upgrade safely

**If you're on Python 3.10:**
- You can now use sphinx-exercise v1.1.1
- Sphinx 8 support is limited to 8.1.x on Python 3.10
- All features work identically to newer Python versions

## 🐛 Bug Fixes

- Fixed test fixtures to handle Sphinx 8.1.x vs 8.2+ XML output differences
- Ensured consistent test behavior across all Python/Sphinx combinations

## 📝 Full Changelog

For complete details, see the [CHANGELOG.md](https://github.com/executablebooks/sphinx-exercise/blob/main/CHANGELOG.md).

## 🙏 Acknowledgments

Thank you to all contributors and users who reported the need for Python 3.10 support!
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dynamic = ["version"]
description = "A Sphinx extension for producing exercises and solutions."
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.11"
requires-python = ">=3.10"
authors = [
{ name = "QuantEcon", email = "[email protected]" },
]
Expand All @@ -22,6 +22,7 @@ classifiers = [
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
Expand Down
2 changes: 1 addition & 1 deletion sphinx_exercise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
:license: MIT, see LICENSE for details.
"""

__version__ = "1.1.0"
__version__ = "1.1.1"

from pathlib import Path
from typing import Any, Dict, Set, Union, cast
Expand Down
7 changes: 6 additions & 1 deletion tests/test_exercise_references.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
import pytest
import sphinx

SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}"
# Sphinx 8.1.x (Python 3.10 only) has different XML output than 8.2+
# Use .sphinx8.1 for 8.1.x, .sphinx8 for 8.2+ (the standard)
if sphinx.version_info[0] == 8 and sphinx.version_info[1] == 1:
SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}.{sphinx.version_info[1]}"
else:
SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}"


@pytest.mark.sphinx("html", testroot="mybook")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<p>This is a reference <a class="reference internal" href="_enum_mathtitle_label.html#test-exc-label-math"><span class="std std-numref">Exercise 1</span></a>.</p>
<p>This is a second reference <a class="reference internal" href="_enum_mathtitle_label.html#test-exc-label-math"><span class="std std-numref">some text 1</span></a>.</p>
<p>This is a third reference <a class="reference internal" href="_enum_mathtitle_label.html#test-exc-label-math"><span class="std std-numref">some text 1</span></a>.</p>
<p>This is a fourth reference <a class="reference internal" href="_enum_mathtitle_label.html#test-exc-label-math"><span class="std std-numref">some text Exercise</span></a>.</p>
<p class="topless"><a href="_enum_numref_title.html" title="previous chapter">_enum_numref_title</a></p>
<p class="topless"><a href="_unenum_mathtitle_label.html" title="next chapter">_unenum_mathtitle_label</a></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<p>This is a reference <a class="reference internal" href="_enum_notitle_label.html#text-exc-notitle"><span class="std std-numref">Exercise 2</span></a>.</p>
<p>This is a second reference <a class="reference internal" href="_enum_notitle_label.html#text-exc-notitle"><span class="std std-numref">some text 2</span></a>.</p>
<p>This is a third reference <a class="reference internal" href="_enum_notitle_label.html#text-exc-notitle"><span class="std std-numref">some text 2</span></a>.</p>
<p>This is a fourth reference <a class="reference internal" href="_enum_notitle_label.html#text-exc-notitle"><span class="std std-numref">some text Exercise</span></a>.</p>
<p class="topless"><a href="_enum_ref_mathtitle.html" title="previous chapter">_enum_ref_mathtitle</a></p>
<p class="topless"><a href="_enum_numref_title.html" title="next chapter">_enum_numref_title</a></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<p>This reference does not include math <a class="reference internal" href="_enum_title_class_label.html#test-exc-label"><span class="std std-numref">some 3 text %s test Exercise</span></a>.</p>
<p>This reference does not include math <a class="reference internal" href="_enum_title_class_label.html#test-exc-label"><span class="std std-numref">some 3 text %s test</span></a>.</p>
<p>This reference does not include math <a class="reference internal" href="_enum_title_class_label.html#test-exc-label"><span class="std std-numref">some Exercise text %s test</span></a>.</p>
<p>This reference does not include math <a class="reference internal" href="_enum_title_class_label.html#test-exc-label"><span class="std std-numref">some Exercise text 3 test</span></a>.</p>
<p>This reference does not include math <a class="reference internal" href="_enum_title_class_label.html#test-exc-label"><span class="std std-numref">some 3 text test</span></a>.</p>
<p>This reference includes math <a class="reference internal" href="_enum_mathtitle_label.html#test-exc-label-math"><span class="std std-numref">some 1 text %s test Exercise</span></a>.</p>
<p>This reference includes math <a class="reference internal" href="_enum_mathtitle_label.html#test-exc-label-math"><span class="std std-numref">some 1 text %s test</span></a>.</p>
<p>This reference includes math <a class="reference internal" href="_enum_mathtitle_label.html#test-exc-label-math"><span class="std std-numref">some Exercise text %s test</span></a>.</p>
<p>This reference includes math <a class="reference internal" href="_enum_mathtitle_label.html#test-exc-label-math"><span class="std std-numref">some Exercise text 1 test</span></a>.</p>
<p>This reference includes math <a class="reference internal" href="_enum_mathtitle_label.html#test-exc-label-math"><span class="std std-numref">some 1 text test</span></a>.</p>
<p class="topless"><a href="_unenum_numref_mathtitle.html" title="previous chapter">_unenum_numref_mathtitle</a></p>
<p class="topless"><a href="_enum_duplicate_label.html" title="next chapter">_enum_duplicate_label</a></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<p>This is a reference <a class="reference internal" href="_enum_title_class_label.html#test-exc-label"><span class="std std-numref">Exercise 3</span></a>.</p>
<p>This is a second reference <a class="reference internal" href="_enum_title_class_label.html#test-exc-label"><span class="std std-numref">some text 3</span></a>.</p>
<p>This is a third reference <a class="reference internal" href="_enum_title_class_label.html#test-exc-label"><span class="std std-numref">some text 3</span></a>.</p>
<p>This is a fourth reference <a class="reference internal" href="_enum_title_class_label.html#test-exc-label"><span class="std std-numref">some text Exercise</span></a>.</p>
<p class="topless"><a href="_enum_numref_notitle.html" title="previous chapter">_enum_numref_notitle</a></p>
<p class="topless"><a href="_enum_numref_mathtitle.html" title="next chapter">_enum_numref_mathtitle</a></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<p>This is a reference <a class="reference internal" href="_enum_mathtitle_label.html#test-exc-label-math"><span class="std std-numref">Exercise 1</span></a>.</p>
<p>This is a second reference <a class="reference internal" href="_enum_mathtitle_label.html#test-exc-label-math"><span class="std std-ref">some text</span></a>.</p>
<p class="topless"><a href="_enum_ref_title.html" title="previous chapter">_enum_ref_title</a></p>
<p class="topless"><a href="_enum_numref_notitle.html" title="next chapter">_enum_numref_notitle</a></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<p>This is a reference <a class="reference internal" href="_enum_notitle_label.html#text-exc-notitle"><span class="std std-numref">Exercise 2</span></a>.</p>
<p>This is a second reference <a class="reference internal" href="_enum_notitle_label.html#text-exc-notitle"><span class="std std-ref">some text</span></a>.</p>
<p class="topless"><a href="_enum_title_nolabel.html" title="previous chapter">_enum_title_nolabel</a></p>
<p class="topless"><a href="_enum_ref_title.html" title="next chapter">_enum_ref_title</a></p>
4 changes: 4 additions & 0 deletions tests/test_exercise_references/_enum_ref_title.sphinx8.1.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<p>This is a reference <a class="reference internal" href="_enum_title_class_label.html#test-exc-label"><span class="std std-numref">Exercise 3</span></a>.</p>
<p>This is a second reference <a class="reference internal" href="_enum_title_class_label.html#test-exc-label"><span class="std std-ref">some text</span></a>.</p>
<p class="topless"><a href="_enum_ref_notitle.html" title="previous chapter">_enum_ref_notitle</a></p>
<p class="topless"><a href="_enum_ref_mathtitle.html" title="next chapter">_enum_ref_mathtitle</a></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<p>This is a reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">unen-exc-label-math</span></code>.</p>
<p>This is a second reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">some</span> <span class="pre">text</span> <span class="pre">%s</span></code>.</p>
<p>This is a third reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">some</span> <span class="pre">text</span> <span class="pre">{number}</span></code>.</p>
<p>This is a fourth reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">some</span> <span class="pre">text</span> <span class="pre">{name}</span></code>.</p>
<p class="topless"><a href="_unenum_numref_title.html" title="previous chapter">_unenum_numref_title</a></p>
<p class="topless"><a href="_enum_numref_placeholders.html" title="next chapter">_enum_numref_placeholders</a></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<p>This is a reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">unen-exc-notitle</span></code>.</p>
<p>This is a second reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">some</span> <span class="pre">text</span> <span class="pre">%s</span></code>.</p>
<p>This is a third reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">some</span> <span class="pre">text</span> <span class="pre">{number}</span></code>.</p>
<p>This is a fourth reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">some</span> <span class="pre">text</span> <span class="pre">{name}</span></code>.</p>
<p class="topless"><a href="_unenum_ref_mathtitle.html" title="previous chapter">_unenum_ref_mathtitle</a></p>
<p class="topless"><a href="_unenum_numref_title.html" title="next chapter">_unenum_numref_title</a></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<p>This is a reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">unen-exc-label</span></code>.</p>
<p>This is a second reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">some</span> <span class="pre">text</span> <span class="pre">%s</span></code>.</p>
<p>This is a third reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">some</span> <span class="pre">text</span> <span class="pre">{number}</span></code>.</p>
<p>This is a fourth reference <code class="xref std std-numref docutils literal notranslate"><span class="pre">some</span> <span class="pre">text</span> <span class="pre">{name}</span></code>.</p>
<p class="topless"><a href="_unenum_numref_notitle.html" title="previous chapter">_unenum_numref_notitle</a></p>
<p class="topless"><a href="_unenum_numref_mathtitle.html" title="next chapter">_unenum_numref_mathtitle</a></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<p>This is a reference <a class="reference internal" href="_unenum_mathtitle_label.html#unen-exc-label-math"><span class="std std-ref">Exercise</span></a>.</p>
<p>This is a second reference <a class="reference internal" href="_unenum_mathtitle_label.html#unen-exc-label-math"><span class="std std-ref">some text</span></a>.</p>
<p class="topless"><a href="_unenum_ref_title.html" title="previous chapter">_unenum_ref_title</a></p>
<p class="topless"><a href="_unenum_numref_notitle.html" title="next chapter">_unenum_numref_notitle</a></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<p>This is a reference <a class="reference internal" href="_unenum_notitle_label.html#unen-exc-notitle"><span class="std std-ref">Exercise</span></a>.</p>
<p>This is a second reference <a class="reference internal" href="_unenum_notitle_label.html#unen-exc-notitle"><span class="std std-ref">some text</span></a>.</p>
<p class="topless"><a href="_unenum_title_nolabel.html" title="previous chapter">_unenum_title_nolabel</a></p>
<p class="topless"><a href="_unenum_ref_title.html" title="next chapter">_unenum_ref_title</a></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<p>This is a reference <a class="reference internal" href="_unenum_title_class_label.html#unen-exc-label"><span class="std std-ref">Exercise</span></a>.</p>
<p>This is a second reference <a class="reference internal" href="_unenum_title_class_label.html#unen-exc-label"><span class="std std-ref">some text</span></a>.</p>
<p class="topless"><a href="_unenum_ref_notitle.html" title="previous chapter">_unenum_ref_notitle</a></p>
<p class="topless"><a href="_unenum_ref_mathtitle.html" title="next chapter">_unenum_ref_mathtitle</a></p>
7 changes: 6 additions & 1 deletion tests/test_gateddirective.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ def strip_escseq(text: str) -> str:
return re.sub(r"\x1b\[[0-9;]*m", "", text)


SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}"
# Sphinx 8.1.x (Python 3.10 only) has different XML output than 8.2+
# Use .sphinx8.1 for 8.1.x, .sphinx8 for 8.2+ (the standard)
if sphinx.version_info[0] == 8 and sphinx.version_info[1] == 1:
SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}.{sphinx.version_info[1]}"
else:
SPHINX_VERSION = f".sphinx{sphinx.version_info[0]}"


@pytest.mark.sphinx("html", testroot="gateddirective")
Expand Down
9 changes: 9 additions & 0 deletions tests/test_gateddirective/exercise-gated-0.sphinx8.1.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div class="exercise admonition" id="gated-exercise-1">
<p class="admonition-title"><span class="caption-number">Exercise 3 </span></p>
<section id="exercise-content">
<p>Replicate this figure using matplotlib</p>
<figure class="align-default">
<img alt="_images/sphx_glr_cohere_001_2_0x.png" src="_images/sphx_glr_cohere_001_2_0x.png"/>
</figure>
</section>
</div>
8 changes: 8 additions & 0 deletions tests/test_gateddirective/exercise-gated-1.sphinx8.1.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="exercise admonition" id="gated-exercise-2">
<p class="admonition-title"><span class="caption-number">Exercise 4 </span> (Replicate Matplotlib Plot)</p>
<section id="exercise-content">
<figure class="align-default">
<img alt="_images/sphx_glr_cohere_001_2_0x.png" src="_images/sphx_glr_cohere_001_2_0x.png"/>
</figure>
</section>
</div>
Loading