Skip to content

Conversation

@mmcky
Copy link
Member

@mmcky mmcky commented Oct 21, 2025

Summary

Modernizes the test suite to support Python 3.11-3.13 and Sphinx 6-8, eliminating all deprecation warnings and updating dependency constraints.

Changes

Python & Sphinx Support

  • Python: Updated minimum from 3.9 to 3.11, added support for 3.12 and 3.13
  • Sphinx: Updated from 3.5-7.x to 6.1-8.x support
  • Testing: 9 tox environments (3 Python versions × 3 Sphinx versions)

Deprecation Fixes

  • Fixed Node.traverse()Node.findall() (Sphinx 8 deprecation)
  • Fixed Pathos.fspath(Path) for path handling
  • Fixed matplotlib API: cohere() positional → keyword arguments

Dependency Updates

  • myst-nb: ~=1.0.0>=1.1.0 (enables v1.3.0 with deprecation fixes)
  • pytest: ~=8.0.0>=8.0 (enables v8.4.2 with improvements)
  • matplotlib: >=3.7>=3.8

Test Infrastructure

  • Implemented Sphinx-version-specific test fixtures (.sphinx6, .sphinx7, .sphinx8)
  • Added SPHINX_VERSION fixture in conftest.py
  • Regenerated all test fixtures for Sphinx 6, 7, and 8

Documentation

  • Updated CHANGELOG.md with v1.0.0 and v1.0.1 release information

Test Results

✅ All 110 tests passing across 9 environments
Zero warnings from all sources (sphinx, myst-nb, matplotlib, pytest)

mmcky added 5 commits October 21, 2025 15:16
- Update pyproject.toml: require Python >=3.11, Sphinx >=6.1, matplotlib >=3.8
- Update tox.ini: add 9 test environments (py311/312/313 × sphinx6/7/8)
- Fix deprecation warnings:
  - Use os.path.splitext() instead of string operations (RemovedInSphinx90Warning)
  - Update sphinx.util.console import path
- Implement Sphinx-version-specific regression fixtures:
  - Generate separate .sphinx6/.sphinx7/.sphinx8 fixtures for HTML and XML
  - Track actual Sphinx output differences without filtering
  - Add ipykernel process ID normalization for test stability
- All 110 tests pass across all 9 Python/Sphinx combinations
- Update CHANGELOG.md with v1.0.0 and v1.0.1 release information
- Fix deprecated matplotlib.axes.Axes.cohere() API usage in test files
  - Change from positional args to keyword args (NFFT=, Fs=)
  - Eliminates MatplotlibDeprecationWarning from test output
- Regenerate Sphinx 8 test fixtures to reflect corrected test code
- All 110 tests passing with only external myst_nb warnings remaining
- Change from myst-nb~=1.0.0 to myst-nb>=1.1.0
- myst-nb v1.1.0+ uses Node.findall() instead of deprecated Node.traverse()
- Eliminates PendingDeprecationWarning and RemovedInSphinx90Warning
- All 110 tests pass with ZERO warnings
- Update fixtures to reflect myst-nb >=1.1.0 output (no warnings)
- Remove MatplotlibDeprecationWarning from fixture files
- Similar to myst-nb update, the ~=8.0.0 constraint was locking pytest to 8.0.x
- Latest pytest is 8.4.2 with bug fixes and improvements
- All 110 tests passing with pytest 8.4.2
@mmcky mmcky changed the title MAINT: review and upgrade all tests with fixes for warnings MAINT: Update test suite for Python 3.11-3.13 and Sphinx 6-8 compatibility Oct 21, 2025
mmcky added 9 commits October 21, 2025 16:25
- Fix E402: Move sphinx.locale import to top of file in nodes.py
- Add newline at end of MANIFEST.in
- Apply ruff-format line wrapping for long lines
Matplotlib generates platform/version-specific content hashes for images.
This causes test failures when comparing fixtures generated on different
platforms (macOS vs Linux) or with different package versions.

Solution: Add regex pattern to FileRegression to normalize all matplotlib
image hashes to 'IMAGEHASH.png', making tests platform-independent.

Fixes CI test failures in test_gateddirective.py.
Match CI test matrix to tox configuration:
- Python versions: 3.11, 3.12, 3.13
- Sphinx versions: 6, 7, 8
- Total: 9 test combinations

This ensures CI tests the same environments as local tox testing,
providing better coverage and catching version-specific issues.
The function strip_escape_sequences was removed from sphinx.util.console
in later versions. Add try/except import with fallback implementation.

Also update tox.ini to properly install Sphinx version-specific dependencies
by explicitly listing all testing dependencies in deps rather than using
the 'testing' extra which includes a broad Sphinx version range.

Fixes CI failure on Python 3.13 + Sphinx 6 combination.
Use constrain_package_deps and use_frozen_constraints to ensure
that the Sphinx version specified in tox deps takes precedence over
the package's own dependency declaration (sphinx>=6.1).

This creates a constraints file that locks the Sphinx version during
package dependency installation, preventing pip from upgrading to the
latest version.

Verified working:
- py311-sphinx6: Sphinx 6.2.1
- py311-sphinx7: Sphinx 7.4.7
- py311-sphinx8: Sphinx 8.2.3
Now that constrain_package_deps is working correctly, we can use
the 'testing' extras from pyproject.toml instead of manually listing
all dependencies.

This is more maintainable - when testing dependencies change in
pyproject.toml, they automatically apply to tox without needing
to update both files.

The constraints mechanism ensures Sphinx version from deps still
takes precedence over the package's sphinx>=6.1,<9 requirement.
The sphinx.testing.path.path object in Sphinx <7.2 doesn't have an
.absolute() method. The path is already absolute, so we can use it
directly without calling .absolute().

This fixes the AttributeError: 'path' object has no attribute 'absolute'
error that was causing all 110 tests to fail on Sphinx 6.

The version check ensures Sphinx 7.2+ continues to use pathlib.Path
with .absolute() as before.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR modernizes the test suite to support Python 3.11-3.13 and Sphinx 6-8, eliminating deprecation warnings and updating dependencies for better compatibility.

  • Updates Python support from 3.9-3.10 to 3.11-3.13
  • Updates Sphinx support from 5-7 to 6.1-8
  • Implements version-specific test fixtures to handle Sphinx output differences
  • Fixes deprecated API usage in Sphinx and matplotlib

Reviewed Changes

Copilot reviewed 154 out of 155 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pyproject.toml Updates Python version requirements (3.11+), Sphinx constraints (6.1-8), and dependency version ranges
tox.ini Configures test matrix for 3 Python versions × 3 Sphinx versions (9 environments)
.github/workflows/ci.yml Updates CI matrix to test Python 3.11-3.13 with Sphinx 6-8
tests/conftest.py Adds regex patterns for normalizing image hashes and process IDs in test fixtures
tests/test_*.py Adds SPHINX_VERSION fixture support and version-specific test file extensions
tests/test_gateddirective.py Adds fallback for deprecated strip_escape_sequences function
tests/books/test-gateddirective/*.md Updates matplotlib cohere() calls to use keyword arguments
sphinx_exercise/*.py Minor code formatting improvements and import organization
tests/test_/.sphinx{6,7,8}.{html,xml} Adds version-specific test fixtures for Sphinx 6, 7, and 8
CHANGELOG.md Documents v1.0.0 and v1.0.1 releases

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

:licences: see LICENSE for details
"""

import os
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The os import is added but only used for os.path.splitext(). Consider using pathlib.Path instead for consistency with modern Python practices, or document why os.path is preferred here.

Copilot uses AI. Check for mistakes.
docname = self.env.docname # for builder such as JupyterBuilder that don't support current_docname
docpath = self.env.doc2path(docname)
path = docpath[: docpath.rfind(".")]
path = os.path.splitext(docpath)[0]
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] While os.path.splitext() works correctly, the previous implementation using string slicing with rfind(".") would fail on paths without extensions. This change is an improvement, but consider using pathlib.Path(docpath).stem for a more robust solution.

Copilot uses AI. Check for mistakes.
mmcky added 2 commits October 22, 2025 12:59
Use pathlib.Path.with_suffix('') instead of os.path.splitext()[0] for
better consistency with modern Python practices. This removes the os
import which was only used for this single operation.
Modernize all remaining os.path operations to use pathlib.Path for
consistency:
- sphinx_exercise/__init__.py: Use Path for package/locale directory
- sphinx_exercise/post_transforms.py: Use Path.with_suffix('')
- sphinx_exercise/translations/_convert.py: Use Path.resolve()

This completes the migration to pathlib throughout the codebase,
keeping only os.sep in tests where it's appropriate for path
separator normalization.
@mmcky mmcky merged commit 4b49053 into main Oct 22, 2025
12 checks passed
@mmcky mmcky deleted the maint-tests branch October 22, 2025 02:12
@moorepants
Copy link

Hi, I maintain the conda forge recipe for this package and conda forge builds for all non-end-of-life Python versions in general. Python 3.10 still has a year of life left. If you can support Python 3.10, that is helpful for downstream users.

@mmcky
Copy link
Member Author

mmcky commented Oct 22, 2025

Hi, I maintain the conda forge recipe for this package and conda forge builds for all non-end-of-life Python versions in general. Python 3.10 still has a year of life left. If you can support Python 3.10, that is helpful for downstream users.

Thanks @moorepants -- appreciate the info. I'll try to get a python=3.10 PR together soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants