From ab86127e4e3f2e9aa33ea39dd28eb2dc749abc40 Mon Sep 17 00:00:00 2001 From: dex0shubham Date: Fri, 21 Aug 2026 16:03:22 +0100 Subject: [PATCH] test: guard fastapi-dependent modules so collection succeeds without the explorer extra Closes #1167 --- tests/explorer/test_explorer_api.py | 19 +++++++++---------- tests/explorer/test_explorer_auth.py | 17 ++++++++--------- tests/explorer/test_ontology_dns_pinning.py | 7 ++++++- tests/explorer/test_ontology_ssrf.py | 7 ++++++- tests/explorer/test_ontology_subissue3.py | 19 +++++++++---------- .../test_provenance_manager_wiring.py | 17 +++++++++++------ tests/explorer/test_provenance_route.py | 9 ++++++++- tests/explorer/test_sparql_route.py | 19 +++++++++---------- tests/explorer/test_vocabulary.py | 17 ++++++++++++----- tests/test_security_regression.py | 7 ++++++- 10 files changed, 84 insertions(+), 54 deletions(-) diff --git a/tests/explorer/test_explorer_api.py b/tests/explorer/test_explorer_api.py index 18d7fcaf..dd8fa18b 100644 --- a/tests/explorer/test_explorer_api.py +++ b/tests/explorer/test_explorer_api.py @@ -9,16 +9,15 @@ import networkx as nx import pytest from semantica.context.context_graph import ContextGraph -from semantica.explorer.app import create_app -from semantica.explorer.session import GraphSession +# fastapi ships in the optional `explorer` extra, not in `dev`, so this module +# must skip rather than fail collection when it is absent. The guard has to sit +# above the import below, which pulls fastapi in transitively. +pytest.importorskip("fastapi") -try: - from starlette.testclient import TestClient -except ImportError: - pytest.skip( - "starlette TestClient is required for explorer tests. Install semantica[explorer].", - allow_module_level=True, - ) +from semantica.explorer.app import create_app # noqa: E402 +from semantica.explorer.session import GraphSession # noqa: E402 + +from starlette.testclient import TestClient # noqa: E402 @@ -1104,7 +1103,7 @@ class TestBidirectionalPathRoute: # _classify_distance unit tests — issue #472 # --------------------------------------------------------------------------- -from semantica.utils.helpers import classify_path_distance +from semantica.utils.helpers import classify_path_distance # noqa: E402 class _FakeSimilarity: diff --git a/tests/explorer/test_explorer_auth.py b/tests/explorer/test_explorer_auth.py index e29461d2..aedcd938 100644 --- a/tests/explorer/test_explorer_auth.py +++ b/tests/explorer/test_explorer_auth.py @@ -13,16 +13,15 @@ browsers can't set custom headers on a WebSocket handshake. import pytest from semantica.context.context_graph import ContextGraph -from semantica.explorer.app import create_app -from semantica.explorer.session import GraphSession +# fastapi ships in the optional `explorer` extra, not in `dev`, so this module +# must skip rather than fail collection when it is absent. The guard has to sit +# above the import below, which pulls fastapi in transitively. +pytest.importorskip("fastapi") -try: - from starlette.testclient import TestClient -except ImportError: - pytest.skip( - "starlette TestClient is required for explorer tests. Install semantica[explorer].", - allow_module_level=True, - ) +from semantica.explorer.app import create_app # noqa: E402 +from semantica.explorer.session import GraphSession # noqa: E402 + +from starlette.testclient import TestClient # noqa: E402 def _build_sample_graph() -> ContextGraph: diff --git a/tests/explorer/test_ontology_dns_pinning.py b/tests/explorer/test_ontology_dns_pinning.py index a68ff192..4801a22f 100644 --- a/tests/explorer/test_ontology_dns_pinning.py +++ b/tests/explorer/test_ontology_dns_pinning.py @@ -27,7 +27,12 @@ import threading import pytest -from semantica.explorer.routes import ontology as ontology_mod +# fastapi ships in the optional `explorer` extra, not in `dev`, so this module +# must skip rather than fail collection when it is absent. The guard has to sit +# above the import below, which pulls fastapi in transitively. +pytest.importorskip("fastapi") + +from semantica.explorer.routes import ontology as ontology_mod # noqa: E402 def _start_local_server(): diff --git a/tests/explorer/test_ontology_ssrf.py b/tests/explorer/test_ontology_ssrf.py index 8613275c..c0013d9b 100644 --- a/tests/explorer/test_ontology_ssrf.py +++ b/tests/explorer/test_ontology_ssrf.py @@ -21,7 +21,12 @@ from unittest.mock import MagicMock, patch import pytest -from semantica.explorer.routes import ontology as ontology_mod +# fastapi ships in the optional `explorer` extra, not in `dev`, so this module +# must skip rather than fail collection when it is absent. The guard has to sit +# above the import below, which pulls fastapi in transitively. +pytest.importorskip("fastapi") + +from semantica.explorer.routes import ontology as ontology_mod # noqa: E402 def _fake_getaddrinfo(host, *args, **kwargs): diff --git a/tests/explorer/test_ontology_subissue3.py b/tests/explorer/test_ontology_subissue3.py index 56800c50..66a660b0 100644 --- a/tests/explorer/test_ontology_subissue3.py +++ b/tests/explorer/test_ontology_subissue3.py @@ -6,17 +6,16 @@ from urllib.parse import quote import pytest from semantica.context.context_graph import ContextGraph -from semantica.explorer.app import create_app -from semantica.explorer.routes.ontology import OntologyEntry -from semantica.explorer.session import GraphSession +# fastapi ships in the optional `explorer` extra, not in `dev`, so this module +# must skip rather than fail collection when it is absent. The guard has to sit +# above the import below, which pulls fastapi in transitively. +pytest.importorskip("fastapi") -try: - from starlette.testclient import TestClient -except ImportError: - pytest.skip( - "starlette TestClient is required for explorer tests. Install semantica[explorer].", - allow_module_level=True, - ) +from semantica.explorer.app import create_app # noqa: E402 +from semantica.explorer.routes.ontology import OntologyEntry # noqa: E402 +from semantica.explorer.session import GraphSession # noqa: E402 + +from starlette.testclient import TestClient # noqa: E402 def _build_ontology_graph() -> ContextGraph: diff --git a/tests/explorer/test_provenance_manager_wiring.py b/tests/explorer/test_provenance_manager_wiring.py index 282a48cc..86d9ad12 100644 --- a/tests/explorer/test_provenance_manager_wiring.py +++ b/tests/explorer/test_provenance_manager_wiring.py @@ -5,13 +5,18 @@ Tests for ProvenanceManager wiring into Explorer routes and application startup. from unittest.mock import patch import pytest -from starlette.testclient import TestClient +# fastapi ships in the optional `explorer` extra, not in `dev`, so this module +# must skip rather than fail collection when it is absent. The guard has to sit +# above the starlette/explorer imports below, which need that extra. +pytest.importorskip("fastapi") -from semantica.context.context_graph import ContextGraph -from semantica.explorer.app import create_app -from semantica.explorer.session import GraphSession -from semantica.provenance import ProvenanceManager -from semantica.provenance.storage import SQLiteStorage +from starlette.testclient import TestClient # noqa: E402 + +from semantica.context.context_graph import ContextGraph # noqa: E402 +from semantica.explorer.app import create_app # noqa: E402 +from semantica.explorer.session import GraphSession # noqa: E402 +from semantica.provenance import ProvenanceManager # noqa: E402 +from semantica.provenance.storage import SQLiteStorage # noqa: E402 @pytest.fixture diff --git a/tests/explorer/test_provenance_route.py b/tests/explorer/test_provenance_route.py index aa2b9d72..caea248a 100644 --- a/tests/explorer/test_provenance_route.py +++ b/tests/explorer/test_provenance_route.py @@ -2,7 +2,14 @@ from types import SimpleNamespace -from semantica.explorer.routes.provenance import ( +import pytest + +# fastapi ships in the optional `explorer` extra, not in `dev`, so this module +# must skip rather than fail collection when it is absent. The guard has to sit +# above the import below, which pulls fastapi in transitively. +pytest.importorskip("fastapi") + +from semantica.explorer.routes.provenance import ( # noqa: E402 _add_chain_edges, _build_provenance, _render_markdown, diff --git a/tests/explorer/test_sparql_route.py b/tests/explorer/test_sparql_route.py index 1f619aa7..b2335f80 100644 --- a/tests/explorer/test_sparql_route.py +++ b/tests/explorer/test_sparql_route.py @@ -14,18 +14,17 @@ from unittest.mock import patch import pytest from semantica.context.context_graph import ContextGraph -from semantica.explorer.app import create_app -from semantica.explorer.session import GraphSession +# fastapi ships in the optional `explorer` extra, not in `dev`, so this module +# must skip rather than fail collection when it is absent. The guard has to sit +# above the import below, which pulls fastapi in transitively. +pytest.importorskip("fastapi") -try: - from starlette.testclient import TestClient -except ImportError: - pytest.skip( - "starlette TestClient is required for explorer tests. Install semantica[explorer].", - allow_module_level=True, - ) +from semantica.explorer.app import create_app # noqa: E402 +from semantica.explorer.session import GraphSession # noqa: E402 -import semantica.explorer.routes.sparql as sparql_mod +from starlette.testclient import TestClient # noqa: E402 + +import semantica.explorer.routes.sparql as sparql_mod # noqa: E402 def _build_sample_graph() -> ContextGraph: diff --git a/tests/explorer/test_vocabulary.py b/tests/explorer/test_vocabulary.py index 3de0f3e9..b3e67a20 100644 --- a/tests/explorer/test_vocabulary.py +++ b/tests/explorer/test_vocabulary.py @@ -2,12 +2,19 @@ from unittest.mock import MagicMock -from fastapi import FastAPI -from fastapi.testclient import TestClient +import pytest -from semantica.explorer.dependencies import get_session -from semantica.explorer.routes.vocabulary import router -from semantica.utils.skos import validate_skos_hierarchy +# fastapi ships in the optional `explorer` extra, not in `dev`, so this module +# must skip rather than fail collection when it is absent. The guard has to sit +# above the import below, which pulls fastapi in transitively. +pytest.importorskip("fastapi") + +from fastapi import FastAPI # noqa: E402 +from fastapi.testclient import TestClient # noqa: E402 + +from semantica.explorer.dependencies import get_session # noqa: E402 +from semantica.explorer.routes.vocabulary import router # noqa: E402 +from semantica.utils.skos import validate_skos_hierarchy # noqa: E402 app = FastAPI() app.include_router(router) diff --git a/tests/test_security_regression.py b/tests/test_security_regression.py index 56ad46de..cc4ae542 100644 --- a/tests/test_security_regression.py +++ b/tests/test_security_regression.py @@ -24,7 +24,12 @@ import pytest # rdf:/rdfs: namespaces) and neither the code nor this test caught it, # since both had the same bug. Importing the real function makes that class # of drift impossible. -from semantica.explorer.routes.sparql import _is_read_only_query +# fastapi ships in the optional `explorer` extra, not in `dev`, so this module +# must skip rather than fail collection when it is absent. The guard has to sit +# above the import below, which pulls fastapi in transitively. +pytest.importorskip("fastapi") + +from semantica.explorer.routes.sparql import _is_read_only_query # noqa: E402 class TestSparqlReadOnlyValidation: