GitHub Issue: sphinx-contrib/spelling#234
Problem: The sphinxcontrib-spelling extension crashes with Sphinx 8.2.3 when docutils.utils.get_source_line(node) returns None for the source parameter.
Error:
TypeError: expected str, bytes or os.PathLike object, not NoneType
Location: sphinxcontrib/spelling/builder.py, line 231
- Examined the existing test suite in
tests/test_builder.py - Analyzed the bug report and traceback
- Identified that the issue occurs when
sourceisNoneand gets passed toosutil.relpath()
Several approaches were attempted:
- Custom directive - Creating nodes without source information
- Transform - Clearing source info after parsing
- Mocking
get_source_line()- ✅ Successfully reproduced the issue
The final approach directly patches docutils.utils.get_source_line() to return (None, lineno), which reliably reproduces the exact condition from issue #234.
Created test_nodes_with_none_source() in tests/test_builder.py:
- Creates a mock extension that patches
get_source_line() - Returns
Nonefor source to trigger the bug - Verifies that spelling checks still work after the fix
Modified sphinxcontrib/spelling/builder.py (lines 231-236):
source, node_lineno = docutils.utils.get_source_line(node)
if source is not None:
source = osutil.relpath(source)
else:
# Some nodes (e.g., programmatically generated) may not have
# source information. Use a placeholder.
source = "<unknown>"-
sphinxcontrib/spelling/builder.py- Added null check before calling
osutil.relpath(source) - Use
"<unknown>"placeholder when source isNone - Follows existing pattern (line 239 already handles
node_linenobeingNone)
- Added null check before calling
-
tests/test_builder.py- Added
test_nodes_with_none_source()test function - Creates mock extension to simulate the bug condition
- Verifies fix handles
Nonesource gracefully
- Added
- ✅ New test fails before fix (reproduces issue #234)
- ✅ New test passes after fix
- ✅ All 69 tests pass
- ✅ No new linting errors
git checkout -b fix-issue-234-none-sourcecommit ea81be98eba67d102a3f4b6829f36664e5d5b8c7
Author: Doug Hellmann <doug@doughellmann.com>
Date: Fri Nov 28 10:06:19 2025 -0500
Fix TypeError when source is None in Sphinx 8.2
Fixes #234
When docutils.utils.get_source_line() returns None for the source
parameter, the code was attempting to call osutil.relpath(None),
which caused a TypeError in Sphinx 8.2.3.
This can occur with programmatically generated nodes or certain
document structures that don't have proper source attribution.
Changes:
- Added null check before calling osutil.relpath() in builder.py
- Use '<unknown>' placeholder when source is None
- Added test case that reproduces the issue and verifies the fix
Co-authored-by: Claude Sonnet 4.5 <ai-assistant@anthropic.com>
sphinxcontrib/spelling/builder.py | 7 +++-
tests/test_builder.py | 74 +++++++++++++++++++++++++++
2 files changed, 80 insertions(+), 1 deletion(-)
-
Testing Strategy: Direct mocking of the problematic function was more reliable than trying to create document structures that naturally trigger the bug.
-
Test Design: The test initially used
pytest.raises(TypeError)which made it pass when the bug was present. This was corrected to fail when the bug exists and pass when fixed. -
Defensive Programming: The fix mirrors the existing pattern in the code where
node_linenois already checked forNonebefore use. -
Compatibility: This issue appears in Sphinx 8.2+ when certain types of nodes (programmatically generated content, synthetic nodes) don't have proper source attribution.
# Run specific test
hatch run test:python -m pytest tests/test_builder.py::test_nodes_with_none_source -v
# Run all builder tests
hatch run test:python -m pytest tests/test_builder.py -v
# Run full test suite
hatch run test:python -m pytest tests/ -v
# Create branch and commit
git checkout -b fix-issue-234-none-source
git add sphinxcontrib/spelling/builder.py tests/test_builder.py
git commit -m "..."This fix was developed through pair programming with Claude Sonnet 4.5 as indicated in the commit co-author attribution.