diff --git a/.github/workflows/pyright-type-checking.yml b/.github/workflows/pyright-type-checking.yml index c1865f236b..77c77743d4 100644 --- a/.github/workflows/pyright-type-checking.yml +++ b/.github/workflows/pyright-type-checking.yml @@ -20,7 +20,9 @@ jobs: - run: uv sync - run: echo "$PWD/.venv/bin" >> $GITHUB_PATH + # No working-directory: pyright reads pyrightconfig.json from the repo root so the + # checked paths live in one place. src/rapidata/service was outside the old scope, + # which is how a dead import there shipped in 3.21.0 and broke every API call. - uses: jakebailey/pyright-action@v2 with: version: v1.1.396 - working-directory: src/rapidata/rapidata_client diff --git a/pyrightconfig.json b/pyrightconfig.json index 8f63a1023c..23cb3ed308 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -1,3 +1,3 @@ { - "include": ["src/rapidata/rapidata_client"] + "include": ["src/rapidata/rapidata_client", "src/rapidata/service"] } diff --git a/src/rapidata/service/services/__init__.py b/src/rapidata/service/services/__init__.py index 0cf244dd35..a8acbe32a4 100644 --- a/src/rapidata/service/services/__init__.py +++ b/src/rapidata/service/services/__init__.py @@ -5,11 +5,11 @@ from rapidata.service.services.flow_service import FlowService from rapidata.service.services.leaderboard_service import LeaderboardService from rapidata.service.services.order_service import OrderService -from rapidata.service.services.pipeline_service import PipelineService +from rapidata.service.services.payment_service import PaymentService from rapidata.service.services.rapid_service import RapidService from rapidata.service.services.signal_service import SignalService +from rapidata.service.services.translation_service import TranslationService from rapidata.service.services.validation_service import ValidationService -from rapidata.service.services.workflow_service import WorkflowService __all__ = [ "AssetService", @@ -19,9 +19,9 @@ "FlowService", "LeaderboardService", "OrderService", - "PipelineService", + "PaymentService", "RapidService", "SignalService", + "TranslationService", "ValidationService", - "WorkflowService", ] diff --git a/tests/service/__init__.py b/tests/service/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/service/test_services_package.py b/tests/service/test_services_package.py new file mode 100644 index 0000000000..22676f765a --- /dev/null +++ b/tests/service/test_services_package.py @@ -0,0 +1,43 @@ +"""Tests that keep ``rapidata.service.services`` importable. + +``openapi_service`` reaches every backend service through a lazy +``from rapidata.service.services._service import ...``, and that import +runs the package ``__init__`` first. So a single stale name in ``__init__`` +breaks *every* API call in the published wheel, not just the service that was +removed — which is how 3.21.0 shipped with a dead ``pipeline_service`` import +and raised ``ModuleNotFoundError`` on any call. +""" + +from __future__ import annotations + +import importlib +from pathlib import Path + +import pytest + +import rapidata.service.services as services_package + + +def _service_modules() -> list[str]: + package_dir = Path(services_package.__file__).parent + return sorted(p.stem for p in package_dir.glob("*_service.py")) + + +class TestServicesPackage: + def test_every_exported_name_is_resolvable(self): + """A name left in ``__all__`` after its module was deleted is the failure mode.""" + for name in services_package.__all__: + assert ( + getattr(services_package, name, None) is not None + ), f"{name} is exported but not bound" + + @pytest.mark.parametrize("module_name", _service_modules()) + def test_every_service_module_is_exported(self, module_name: str): + """Keeps ``__all__`` in sync with the modules actually on disk.""" + module = importlib.import_module(f"rapidata.service.services.{module_name}") + expected = "".join(part.capitalize() for part in module_name.split("_")) + + assert hasattr(module, expected), f"{module_name} has no {expected}" + assert ( + expected in services_package.__all__ + ), f"{expected} is missing from rapidata.service.services.__all__"