Skip to content
Open
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
24 changes: 24 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,30 @@ jobs:
run: sphinx-build -b html . _build
working-directory: docs

tests-no-jsonschema:
name: Test jsonschema uninstalled
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set Up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Update pip
run: python -m pip install --upgrade pip
- name: Install Dependencies
run: |
python -m pip install -e .[test,docs]
python -m pip uninstall -y jsonschema
python -m pip freeze
- name: Run pytest
run: |
python -m pytest -v tests/no_jsonschema_tests.py
- name: Run HTML build
# the docs should build without matplotlib (just issuing warnings)
run: sphinx-build -b html . _build
working-directory: docs

check:

# This job does nothing and is only used for the branch protection
Expand Down
6 changes: 6 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ Using pip

pip install sphinx-needs

To use schema validation features of sphinx-needs, you need to also install ``jsonschema``, which is available *via* the ``schema`` extra:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
To use schema validation features of sphinx-needs, you need to also install ``jsonschema``, which is available *via* the ``schema`` extra:
To use schema validation features of sphinx-needs, you need to also install ``jsonschema``, which is available via the ``schema`` extra:


.. code-block:: bash

pip install sphinx-needs[schema]

If you wish to also use the plotting features of sphinx-needs (see ``needbar`` and ``needpie``), you need to also install ``matplotlib``, which is available *via* the ``plotting`` extra:

.. code-block:: bash
Expand Down
8 changes: 4 additions & 4 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ RUN pip3 install --no-cache-dir \
# Install Sphinx-Needs
RUN \
if [ -n "$NEEDS_VERSION" ] && [ "$NEEDS_VERSION" = "pre-release" ]; then \
pip3 install --no-cache-dir "sphinx-needs[plotting] @ git+https://github.com/useblocks/sphinx-needs"; \
pip3 install --no-cache-dir "sphinx-needs[plotting,schema] @ git+https://github.com/useblocks/sphinx-needs"; \
elif [ -n "$NEEDS_VERSION" ]; then \
pip3 install --no-cache-dir "sphinx-needs[plotting] @ git+https://github.com/useblocks/sphinx-needs@$NEEDS_VERSION"; \
pip3 install --no-cache-dir "sphinx-needs[plotting,schema] @ git+https://github.com/useblocks/sphinx-needs@$NEEDS_VERSION"; \
else \
pip3 install --no-cache-dir sphinx-needs[plotting]; \
pip3 install --no-cache-dir sphinx-needs[plotting,schema]; \
fi

## Clean up
Expand All @@ -61,4 +61,4 @@ git
WORKDIR /sphinxneeds

# Start as user
USER ${DOCKER_USERNAME}
USER ${DOCKER_USERNAME}
6 changes: 6 additions & 0 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ Using pip

pip install sphinx-needs

To use schema validation features of sphinx-needs, you need to also install ``jsonschema``, which is available *via* the ``schema`` extra:

.. code-block:: bash

pip install sphinx-needs[schema]

If you wish to also use the plotting features of sphinx-needs (see :ref:`needbar` and :ref:`needpie`), you need to also install ``matplotlib``, which is available *via* the ``plotting`` extra:

.. code-block:: bash
Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ dependencies = [
"sphinx>=7.4,<9",
"requests-file~=2.1", # external links
"requests~=2.32", # external links
Copy link
Member

Choose a reason for hiding this comment

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

jsonschema was a dependency before for version 5.1.0 as we see in this PR as it was used to check the schema of imported needs.json files. I think that will still be required. This is a basic functionality. So I would only add a group schema-formats that only cares for the additional formats dependencies.

Copy link
Author

Choose a reason for hiding this comment

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

valid, will fix this

"jsonschema[format]>=3.2.0", # schema validation for needsimport and ontology
"sphinx-data-viewer~=0.1.5", # needservice debug output
"sphinxcontrib-jquery~=4.0", # needed for datatables in sphinx>=6
"tomli; python_version < '3.11'", # for needs_from_toml configuration
Expand All @@ -40,9 +39,13 @@ dependencies = [

[project.optional-dependencies]
plotting = ["matplotlib>=3.3.0"] # for needpie / needbar
schema = [
"jsonschema[format]>=3.2.0",
Copy link
Member

@ubmarco ubmarco Oct 7, 2025

Choose a reason for hiding this comment

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

We should split this, e.g. into groups schema and schema-formats. If jsonschema is available, all validations except the string patterns are possible. jsonschema might already be installed in some environments by other libraries.
If schema-formats is not installed, it would remove these dependencies:

 + arrow==1.3.0
 + fqdn==1.5.1
 + isoduration==20.11.0
 + jsonpointer==3.0.0
 + rfc3339-validator==0.1.4
 + rfc3987==1.3.8
 + types-python-dateutil==2.9.0.20250822
 + uri-template==1.3.0
 + webcolors==24.11.1

jsonschema itself only requires:

 + attrs==25.4.0
 + jsonschema==4.25.1
 + jsonschema-specifications==2025.9.1
 + referencing==0.36.2
 + rpds-py==0.27.1

Edit: See below, I propose to only have schema-formats and leave jsonschema as a required dependency.

Copy link
Author

Choose a reason for hiding this comment

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

ok yeah I agree, most of the trouble comes from the [format] extra

Copy link
Author

Choose a reason for hiding this comment

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

Could you clarify what changes are required as a result of this? How can we skip only the string patterns during validation?

] # for schema validation for needsimport and ontology
test = [
"defusedxml~=0.7.1",
"matplotlib>=3.3.0",
"jsonschema[format]>=3.2.0",
"pytest~=8.0",
"pytest-cov~=6.0",
"syrupy~=4.0",
Expand Down
9 changes: 7 additions & 2 deletions sphinx_needs/needsfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
from functools import lru_cache
from typing import Any

from jsonschema import Draft7Validator
from sphinx.environment import BuildEnvironment

from sphinx_needs.config import NeedsSphinxConfig
from sphinx_needs.data import NeedsCoreFields, SphinxNeedsData
from sphinx_needs.logging import get_logger, log_warning
from sphinx_needs.need_item import NeedItem
from sphinx_needs.needs_schema import FieldLiteralValue, FieldsSchema
from sphinx_needs.utils import import_jsonschema

log = get_logger(__name__)

Expand Down Expand Up @@ -276,7 +276,12 @@ def check_needs_data(data: Any) -> Errors:
"""
needs_schema = _load_schema()

validator = Draft7Validator(needs_schema)
jsonschema = import_jsonschema()
if jsonschema is None:
# skipping schema validation due to missing dependency
return Errors([])

validator = jsonschema.Draft7Validator(needs_schema)
schema_errors = list(validator.iter_errors(data))

# In future there may be additional types of validations.
Expand Down
15 changes: 12 additions & 3 deletions sphinx_needs/schema/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

from __future__ import annotations

import typing
from typing import Any, cast

from jsonschema import Draft202012Validator, FormatChecker, ValidationError

from sphinx_needs.config import NeedsSphinxConfig
from sphinx_needs.need_item import NeedItem
from sphinx_needs.schema.config import (
Expand All @@ -27,6 +26,7 @@
save_debug_files,
)
from sphinx_needs.schema.utils import get_properties_from_schema
from sphinx_needs.utils import import_jsonschema
from sphinx_needs.views import NeedsView

# TODO(Marco): error for conflicting unevaluatedProperties
Expand Down Expand Up @@ -62,6 +62,9 @@
_needs_schema: dict[str, Any] = {}
"""The needs schema as it would be written to needs.json, generated by generate_needs_schema()."""

if typing.TYPE_CHECKING:
from jsonschema import ValidationError


def merge_static_schemas(config: NeedsSphinxConfig) -> bool:
"""
Expand Down Expand Up @@ -561,7 +564,13 @@ def get_localschema_errors(

:raises jsonschema_rs.ValidationError: If the schema is invalid cannot be built.
"""
validator = Draft202012Validator(schema, format_checker=FormatChecker())
jsonschema = import_jsonschema()
if jsonschema is None:
# skip schema validation if extra is not installed
return []
validator = jsonschema.Draft202012Validator(
schema, format_checker=jsonschema.FormatChecker()
)
return list(validator.iter_errors(instance=need))


Expand Down
14 changes: 14 additions & 0 deletions sphinx_needs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from collections.abc import Callable
from dataclasses import dataclass
from functools import lru_cache, reduce, wraps
from types import ModuleType
from typing import TYPE_CHECKING, Any, Protocol, TypeVar
from urllib.parse import urlparse

Expand Down Expand Up @@ -419,6 +420,19 @@ def import_matplotlib() -> matplotlib | None:
return matplotlib


@lru_cache
def import_jsonschema() -> ModuleType | None:
"""Import and return matplotlib, or return None if it cannot be imported.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"""Import and return matplotlib, or return None if it cannot be imported.
"""Import and return jsonschema, or return None if it cannot be imported.


Also sets the interactive backend to ``Agg``, if ``DISPLAY`` is not set.
Copy link
Member

Choose a reason for hiding this comment

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

Copy paste error.

"""
try:
import jsonschema
except ImportError:
return None
return jsonschema


def save_matplotlib_figure(
app: Sphinx, figure: FigureBase, basename: str, fromdocname: str
) -> nodes.image:
Expand Down
13 changes: 13 additions & 0 deletions tests/no_jsonschema_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""These tests should only be run in an environment without sphinx_needs installed."""
Copy link
Member

Choose a reason for hiding this comment

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

Not sure how this test relates to what you are implementing. sphinx_needs is certainly installed :)

Copy link
Author

Choose a reason for hiding this comment

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

see the ci.yaml changes, this follows the same structure as the no_matplotlib tests.

The relevant ci job uninstalls the dependency jsonschema and runs only this file

Copy link
Member

Choose a reason for hiding this comment

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

I would expect a positive test that checks whether the build without formats still work.
Then a negative test that checks whether the warning is triggered that certain packages are missing.


import pytest


@pytest.mark.parametrize(
"test_app",
[{"buildername": "html", "srcdir": "doc_test/doc_needsfile"}],
indirect=True,
)
def test_needsfile(test_app):
"""Test the build fails correctly, if matplotlib is not installed."""
Copy link
Member

Choose a reason for hiding this comment

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

Typo?

test_app.build()
Loading