🐛 Register sphinx-needs fields with a typed schema#80
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #80 +/- ##
==========================================
- Coverage 91.04% 90.74% -0.30%
==========================================
Files 31 32 +1
Lines 2847 2875 +28
Branches 306 307 +1
==========================================
+ Hits 2592 2609 +17
- Misses 156 166 +10
- Partials 99 100 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
a9a8ece to
45ebdd0
Compare
What's correct
Issues1. packaging not declared as a direct dep — moderate # source_tracing.py line 8
from packaging.version import Versionpackaging was not in the original imports and is not listed in pyproject.toml dependencies. It's always present transitively (sphinx requires it), but undeclared direct deps are a maintenance hazard. Add "packaging" to dependencies in 2. Wrong type annotation on tmpdir — minor def test_strict_schema_ignores_unset_codelinks_fields(
tmpdir: Path, # ← wrong: pytest's tmpdir is py.path.local
make_app: Callable[..., SphinxTestApp],tmpdir is py.path.local, not pathlib.Path. Works at runtime (py.path.local supports truediv and fspath), but mypy will flag it. The modern replacement is tmp_path: Path, which the existing tests in this repo already use. Switch 3. KeyError risk on the assertion — minor # line 62
assert report["validation_warnings"] == {}, ...If sphinx_needs ever renames or omits this key, this raises KeyError instead of a clean assertion failure. Use report.get("validation_warnings", {}) == {}. 4. Weak "validation actually ran" guard — minor assert report.get("validated_needs_count", 0) >= 1The .get(..., 0) fallback means if sphinx-needs renames validated_needs_count, this assertion trivially passes with 0 >= 1 → False... wait, 0 >= 1 is False, so the test would fail but with a confusing message. Actually more concerning: assert "validated_needs_count" in report, "sphinx-needs didn't write schema_violations.json"
assert report["validated_needs_count"] >= 15. PR description drift — cosmeticThe description says: "A capability check ('schema' in signature(add_extra_option)) keeps sphinx-needs 5 working", but the actual implementation uses Version(sphinx_needs.version) >= Version("6.0.0"). The version comparison is |
|
Addressed in 1 — _USE_FIELD_SCHEMA = "schema" in signature(add_extra_option).parametersConfirmed across the tox matrix: 2 — 3 & 4 — 5 — PR description Updated to match: capability detection + the three-tier |
Without a typed schema, the fields registered for source tracing (project, file, directory and the optional url fields) default to "" on every need. A strict sphinx-needs schema (unevaluatedProperties: false) then reports them as unexpected for needs that never set them. Register them via the modern add_field API (sphinx-needs >= 8), falling back to add_extra_option on older versions (only deprecated on >= 8). Typed fields default to None and are stripped before schema validation, so the false positives go away; sphinx-needs 5 (no schema validation) is unaffected. Adds a regression test (tests/doc_test/schema_strictness) that builds a strict-schema project with a plain need and asserts no schema violation.
Detect typed-field support with an inspect.signature() capability probe instead of a packaging.version comparison, so packaging is no longer a (currently undeclared) dependency. The same probe gates the regression test's skip. Also drop the last packaging use in the src-trace directive: its `sphinx >= 1.6` logging guard is dead code given `sphinx>=7.4`, so import sphinx.util.logging unconditionally. In test_schema_validation: - annotate the fixture as tmp_path: Path (tmpdir is py.path.local, not Path) - use direct dict access for the report assertions so a renamed sphinx-needs key fails loudly instead of being masked by .get()
5d43b9e to
884af80
Compare
Problem
sphinx-codelinks registers its fields (
project,file,directory, and thelocal/remote url fields) via
add_extra_option(app, name)without a schema.Untyped fields default to
""on every need, so when a project enables strictsphinx-needs schema validation (
unevaluatedProperties: false) those emptyfields are reported as unexpected on needs that never set them:
This is the codelinks-side counterpart of the same bug found and fixed in
sphinx-test-reports.
Fix
Register each field with a typed (string) schema so an unset value defaults to
None. sphinx-needs stripsNonefrom the "reduced need" before schemavalidation, so a strict
unevaluatedProperties: falseschema no longer flags afield a need never set (an untyped field stays
"", which is not stripped).Registration adapts to the installed sphinx-needs by capability detection
(no
packagingdependency, matching sphinx-test-reports):add_field(name, description, schema=...)— the modern API, used wherever itis importable.
add_extra_option(app, name, schema=...)whenadd_extra_optionaccepts a
schemakeyword (sphinx-needs >= 6).add_extra_option(app, name)for sphinx-needs 5, which has no schemavalidation, so the empty-default bug cannot arise there anyway.
The
schemacapability is detected with"schema" in signature(add_extra_option).parameters.Test
Adds
tests/doc_test/schema_strictness/+tests/test_schema_validation.py: astrict-schema project with a plain need, asserting no schema violation.
Confirmed red before the fix (
'directory', 'file', 'project' were unexpected) and green after. The test is skipped whenadd_extra_optionhas no
schemakeyword (sphinx-needs < 6).Local checks:
ruff+mypyclean; regression test green on sphinx-needs 6/7/8and correctly skipped on 5; existing src-trace doctree snapshots unchanged.