diff --git a/src/indigoapi/__main__.py b/src/indigoapi/__main__.py index 62653b9..f706b5e 100644 --- a/src/indigoapi/__main__.py +++ b/src/indigoapi/__main__.py @@ -7,7 +7,7 @@ import uvicorn from indigoapi.config import Config -from indigoapi.main import start_api +from indigoapi.server import start_api from ._version import __version__ @@ -61,7 +61,7 @@ def serve(ctx: click.Context): logger.info(f"port {config.server.port}") uvicorn.run( - f"indigoapi.main:{start_api.__name__}", + f"indigoapi.server:{start_api.__name__}", factory=True, host=config.server.host, port=int(config.server.port), diff --git a/src/indigoapi/analyses/__init__.py b/src/indigoapi/analyses/__init__.py index bdc5126..831af5e 100644 --- a/src/indigoapi/analyses/__init__.py +++ b/src/indigoapi/analyses/__init__.py @@ -1,19 +1 @@ -import importlib - -from indigoapi.analyses.loader import load_analyses, load_plugins -from indigoapi.config import Config - -MODULE_NAMES = [] - - -def initialize_analyses(register_all: bool = False): - """Load built-in analyses and user plugins. Call during server startup.""" - global MODULE_NAMES - - # load built-in analyses - package = importlib.import_module(__name__) - MODULE_NAMES = load_analyses(package) - - # load user plugins from config - config = Config.load_config() - load_plugins(config, register_all=register_all) +"""Package containing built-in analysis modules.""" diff --git a/src/indigoapi/analyses/peak_fitting.py b/src/indigoapi/analyses/peak_fitting.py index 40e1907..6ecc549 100644 --- a/src/indigoapi/analyses/peak_fitting.py +++ b/src/indigoapi/analyses/peak_fitting.py @@ -1,7 +1,7 @@ import numpy as np from scipy.optimize import curve_fit -from indigoapi.analyses.decorator import analysis +from indigoapi.analysis_core.decorator import analysis def gaussian(x: np.ndarray, amplitude: float, x0: float, sigma: float) -> np.ndarray: diff --git a/src/indigoapi/analyses/simple_maths.py b/src/indigoapi/analyses/simple_maths.py index cf4b635..e943706 100644 --- a/src/indigoapi/analyses/simple_maths.py +++ b/src/indigoapi/analyses/simple_maths.py @@ -2,7 +2,7 @@ import numpy as np -from indigoapi.analyses.decorator import analysis +from indigoapi.analysis_core.decorator import analysis @analysis() diff --git a/src/indigoapi/analysis_core/__init__.py b/src/indigoapi/analysis_core/__init__.py new file mode 100644 index 0000000..b7d05e8 --- /dev/null +++ b/src/indigoapi/analysis_core/__init__.py @@ -0,0 +1,41 @@ +import importlib + +from indigoapi.config import Config + +from .decorator import analysis +from .loader import get_async_function, load_analyses, load_plugins +from .registry import ( + ANALYSIS_REGISTRY, + AnalysisNotFoundError, + get_analysis, + list_analyses, + register_analysis, +) + +MODULE_NAMES: list[str] = [] + + +def initialize_analyses(register_all: bool = False): + """Load built-in analyses and user plugins. Call during server startup.""" + global MODULE_NAMES + + package = importlib.import_module("indigoapi.analyses") + MODULE_NAMES = load_analyses(package) + + config = Config.load_config() + load_plugins(config, register_all=register_all) + + +__all__ = [ + "analysis", + "get_async_function", + "load_analyses", + "load_plugins", + "ANALYSIS_REGISTRY", + "AnalysisNotFoundError", + "get_analysis", + "list_analyses", + "register_analysis", + "initialize_analyses", + "MODULE_NAMES", +] diff --git a/src/indigoapi/analyses/decorator.py b/src/indigoapi/analysis_core/decorator.py similarity index 82% rename from src/indigoapi/analyses/decorator.py rename to src/indigoapi/analysis_core/decorator.py index 77cd5f3..078fc69 100644 --- a/src/indigoapi/analyses/decorator.py +++ b/src/indigoapi/analysis_core/decorator.py @@ -1,8 +1,8 @@ from collections.abc import Awaitable, Callable from typing import ParamSpec, TypeVar -from indigoapi.analyses.loader import get_async_function -from indigoapi.analyses.registry import register_analysis +from indigoapi.analysis_core.loader import get_async_function +from indigoapi.analysis_core.registry import register_analysis P = ParamSpec("P") R = TypeVar("R") diff --git a/src/indigoapi/analyses/loader.py b/src/indigoapi/analysis_core/loader.py similarity index 96% rename from src/indigoapi/analyses/loader.py rename to src/indigoapi/analysis_core/loader.py index cf57309..d6d213e 100644 --- a/src/indigoapi/analyses/loader.py +++ b/src/indigoapi/analysis_core/loader.py @@ -10,7 +10,7 @@ from git import Repo -from indigoapi.analyses.registry import register_analysis +from indigoapi.analysis_core.registry import register_analysis from indigoapi.config import Config logger = logging.getLogger(__name__) @@ -127,7 +127,7 @@ def load_plugins(config: Config, register_all: bool = False): # if __name__ == "__main__": -# from indigoapi.analyses.registry import list_analyses +# from indigoapi.analysis_core.registry import list_analyses # load_plugins(Config.load_config()) diff --git a/src/indigoapi/analyses/registry.py b/src/indigoapi/analysis_core/registry.py similarity index 100% rename from src/indigoapi/analyses/registry.py rename to src/indigoapi/analysis_core/registry.py diff --git a/src/indigoapi/api/routes.py b/src/indigoapi/api/routes.py index 8ae776f..c42b742 100644 --- a/src/indigoapi/api/routes.py +++ b/src/indigoapi/api/routes.py @@ -5,9 +5,9 @@ from fastapi import APIRouter, HTTPException, Request from fastapi.routing import APIRoute -from indigoapi.analyses.registry import get_analysis, list_analyses +from indigoapi.analysis_core.registry import get_analysis, list_analyses from indigoapi.models import AnalysisRequest, AnalysisResult -from indigoapi.queue_manager import QueueManager +from indigoapi.queue import QueueManager ROUTER = APIRouter() diff --git a/src/indigoapi/queue/__init__.py b/src/indigoapi/queue/__init__.py new file mode 100644 index 0000000..1b7b008 --- /dev/null +++ b/src/indigoapi/queue/__init__.py @@ -0,0 +1,5 @@ +from .cleanup import cleanup_results +from .manager import QueueManager +from .rabbitmq import RabbitMQListener + +__all__ = ["cleanup_results", "QueueManager", "RabbitMQListener"] diff --git a/src/indigoapi/cleanup.py b/src/indigoapi/queue/cleanup.py similarity index 100% rename from src/indigoapi/cleanup.py rename to src/indigoapi/queue/cleanup.py diff --git a/src/indigoapi/queue_manager.py b/src/indigoapi/queue/manager.py similarity index 97% rename from src/indigoapi/queue_manager.py rename to src/indigoapi/queue/manager.py index ced563d..d1b55c2 100644 --- a/src/indigoapi/queue_manager.py +++ b/src/indigoapi/queue/manager.py @@ -6,7 +6,7 @@ from xrpd_toolbox.utils.messenger import DEFAULT_DII_PROCESSED_DESTINATION, Messenger -from indigoapi.analyses.registry import get_analysis +from indigoapi.analysis_core.registry import get_analysis from indigoapi.models import AnalysisRequest, AnalysisResult logging.basicConfig(level=logging.INFO) diff --git a/src/indigoapi/rabbitmq_listener.py b/src/indigoapi/queue/rabbitmq.py similarity index 99% rename from src/indigoapi/rabbitmq_listener.py rename to src/indigoapi/queue/rabbitmq.py index 2d92ce2..9873ab1 100644 --- a/src/indigoapi/rabbitmq_listener.py +++ b/src/indigoapi/queue/rabbitmq.py @@ -9,7 +9,7 @@ from pydantic import BaseModel, Field from indigoapi.models import AnalysisRequest -from indigoapi.queue_manager import QueueManager +from indigoapi.queue import QueueManager logger = logging.getLogger(__name__) diff --git a/src/indigoapi/main.py b/src/indigoapi/server.py similarity index 90% rename from src/indigoapi/main.py rename to src/indigoapi/server.py index 83d8b28..57f3b5f 100644 --- a/src/indigoapi/main.py +++ b/src/indigoapi/server.py @@ -7,12 +7,10 @@ from fastapi import FastAPI from xrpd_toolbox.utils.messenger import Messenger -from indigoapi.analyses import MODULE_NAMES, initialize_analyses +from indigoapi.analysis_core import MODULE_NAMES, initialize_analyses from indigoapi.api.routes import ROUTER -from indigoapi.cleanup import cleanup_results from indigoapi.config import Config -from indigoapi.queue_manager import QueueManager -from indigoapi.rabbitmq_listener import RabbitMQListener +from indigoapi.queue import QueueManager, RabbitMQListener, cleanup_results from . import __version__ @@ -88,7 +86,7 @@ def start_api() -> FastAPI: logger.info(f"version: {__version__}") app = FastAPI( - title="IndigoAPI", + title="indigoapi", version=__version__, description="An API for fast data analysis jobs", lifespan=lifespan, diff --git a/tests/conftest.py b/tests/conftest.py index bf5fc73..61caa6f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,6 @@ import importlib -from indigoapi.analyses.loader import load_analyses +from indigoapi.analysis_core.loader import load_analyses def pytest_configure(): diff --git a/tests/test_api.py b/tests/test_api.py index a55ed70..661ed79 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -4,8 +4,8 @@ from fastapi.testclient import TestClient from indigoapi.config import Config -from indigoapi.main import start_api from indigoapi.models import AnalysisRequest +from indigoapi.server import start_api def test_analysis_flow_with_post(): diff --git a/tests/test_api_routes.py b/tests/test_api_routes.py index 91e4d0d..ad57ff6 100644 --- a/tests/test_api_routes.py +++ b/tests/test_api_routes.py @@ -3,8 +3,8 @@ from fastapi.testclient import TestClient -from indigoapi.main import start_api from indigoapi.models import AnalysisResult +from indigoapi.server import start_api def test_api_health_and_endpoints_routes(): diff --git a/tests/test_cleanup.py b/tests/test_cleanup.py index f005e43..92b8a65 100644 --- a/tests/test_cleanup.py +++ b/tests/test_cleanup.py @@ -4,7 +4,7 @@ import pytest -from indigoapi.cleanup import cleanup_results +from indigoapi.queue import cleanup_results @pytest.mark.asyncio @@ -19,7 +19,7 @@ class FakeQueue: async def fake_sleep(interval): raise asyncio.CancelledError - monkeypatch.setattr("indigoapi.cleanup.asyncio.sleep", fake_sleep) + monkeypatch.setattr("indigoapi.queue.cleanup.asyncio.sleep", fake_sleep) with pytest.raises(asyncio.CancelledError): await cleanup_results(fake_queue, ttl=1, interval=0) @@ -39,7 +39,7 @@ class FakeQueue: async def fake_sleep(interval): raise asyncio.CancelledError - monkeypatch.setattr("indigoapi.cleanup.asyncio.sleep", fake_sleep) + monkeypatch.setattr("indigoapi.queue.cleanup.asyncio.sleep", fake_sleep) with pytest.raises(asyncio.CancelledError): await cleanup_results(fake_queue, ttl=60, interval=0) diff --git a/tests/test_gaussian_fit.py b/tests/test_gaussian_fit.py index bd20d5e..cc6821a 100644 --- a/tests/test_gaussian_fit.py +++ b/tests/test_gaussian_fit.py @@ -3,7 +3,7 @@ from indigoapi.analyses.peak_fitting import gaussian, gaussian_fit from indigoapi.client import AnalysisClient -from indigoapi.main import start_api +from indigoapi.server import start_api def test_gaussian_fit_with_client(): diff --git a/tests/test_loader.py b/tests/test_loader.py index 48acd1f..c2fdfb3 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -1,11 +1,11 @@ import sys -from indigoapi.analyses.loader import ( +from indigoapi.analysis_core.loader import ( clone_github_repo, load_plugins, load_plugins_from_dir, ) -from indigoapi.analyses.registry import ANALYSIS_REGISTRY, list_analyses +from indigoapi.analysis_core.registry import ANALYSIS_REGISTRY, list_analyses from indigoapi.config import Config @@ -28,7 +28,7 @@ def test_loader_load_plugins_from_dir(tmp_path): def test_loader_load_plugins_registers_decorated_functions(tmp_path): plugin_path = tmp_path / "custom_plugin.py" plugin_path.write_text( - "from indigoapi.analyses.decorator import analysis\n" + "from indigoapi.analysis_core.decorator import analysis\n" "@analysis()\n" "def hello(name: str) -> str:\n" " return f'hello {name}'\n" @@ -71,5 +71,5 @@ def test_loader_load_plugins_handles_clone_error(monkeypatch): def fake_clone(repo_url, dest_dir): raise RuntimeError("unable to clone") - monkeypatch.setattr("indigoapi.analyses.loader.clone_github_repo", fake_clone) + monkeypatch.setattr("indigoapi.analysis_core.loader.clone_github_repo", fake_clone) load_plugins(cfg) diff --git a/tests/test_loader_extra.py b/tests/test_loader_extra.py index 1e5d857..0069275 100644 --- a/tests/test_loader_extra.py +++ b/tests/test_loader_extra.py @@ -1,12 +1,12 @@ from unittest.mock import Mock -from indigoapi.analyses.loader import ( +from indigoapi.analysis_core.loader import ( clone_github_repo, get_async_function, load_plugins, load_plugins_from_dir, ) -from indigoapi.analyses.registry import list_analyses +from indigoapi.analysis_core.registry import list_analyses from indigoapi.config import Config @@ -20,7 +20,9 @@ async def coro(): def test_clone_github_repo_force(monkeypatch, tmp_path): dest = tmp_path / "repo" clone_from_mock = Mock() - monkeypatch.setattr("indigoapi.analyses.loader.Repo.clone_from", clone_from_mock) + monkeypatch.setattr( + "indigoapi.analysis_core.loader.Repo.clone_from", clone_from_mock + ) result = clone_github_repo( "https://example.com/repo.git", str(tmp_path), force=True ) @@ -46,7 +48,7 @@ def track_spec(name, location): return real_spec(name, location) monkeypatch.setattr( - "indigoapi.analyses.loader.importlib.util.spec_from_file_location", + "indigoapi.analysis_core.loader.importlib.util.spec_from_file_location", track_spec, ) @@ -68,7 +70,7 @@ def test_load_plugins_with_git_repo(monkeypatch, tmp_path): fake_file.write_text("def hello():\n return 'hello'\n") monkeypatch.setattr( - "indigoapi.analyses.loader.clone_github_repo", lambda url, dest: fake_path + "indigoapi.analysis_core.loader.clone_github_repo", lambda url, dest: fake_path ) load_plugins(cfg, register_all=True) assert "hello" in list_analyses() or True diff --git a/tests/test_plugins.py b/tests/test_plugins.py index cbd13e5..c2642ce 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -2,7 +2,7 @@ import pytest from indigoapi.analyses.peak_fitting import gaussian -from indigoapi.analyses.registry import ( +from indigoapi.analysis_core.registry import ( AnalysisNotFoundError, get_analysis, list_analyses, diff --git a/tests/test_queue_manager.py b/tests/test_queue_manager.py index b083a4d..1091ae6 100644 --- a/tests/test_queue_manager.py +++ b/tests/test_queue_manager.py @@ -5,7 +5,7 @@ from xrpd_toolbox.utils.messenger import Messenger from indigoapi.models import AnalysisRequest -from indigoapi.queue_manager import QueueManager +from indigoapi.queue import QueueManager async def wait_for_result(queue_manager, request_id, timeout=1.0): @@ -26,7 +26,7 @@ async def fake_analysis(number): return number * 2 monkeypatch.setattr( - "indigoapi.analyses.registry.get_analysis", lambda name: fake_analysis + "indigoapi.analysis_core.registry.get_analysis", lambda name: fake_analysis ) job = AnalysisRequest(analysis_name="double", inputs={"number": 2}) @@ -60,7 +60,7 @@ def send_message(self, destination, message): ) monkeypatch.setattr( - "indigoapi.analyses.registry.get_analysis", + "indigoapi.analysis_core.registry.get_analysis", lambda name: (_ for _ in ()).throw(KeyError("missing")), ) diff --git a/tests/test_rabbitmq_listener.py b/tests/test_rabbitmq_listener.py index 9966896..aa80751 100644 --- a/tests/test_rabbitmq_listener.py +++ b/tests/test_rabbitmq_listener.py @@ -7,8 +7,8 @@ import pytest from indigoapi.models import AnalysisRequest -from indigoapi.queue_manager import QueueManager -from indigoapi.rabbitmq_listener import _StompListener +from indigoapi.queue import QueueManager +from indigoapi.queue.rabbitmq import _StompListener @pytest.mark.filterwarnings("ignore::ResourceWarning") @@ -28,7 +28,7 @@ def fake_run_coro_threadsafe(coro, event_loop): return None monkeypatch.setattr( - "indigoapi.rabbitmq_listener.asyncio.run_coroutine_threadsafe", + "indigoapi.queue.rabbitmq.asyncio.run_coroutine_threadsafe", fake_run_coro_threadsafe, ) @@ -54,7 +54,7 @@ def test_stomp_listener_invalid_json(monkeypatch): listener = _StompListener(queue_manager, loop) # type: ignore monkeypatch.setattr( - "indigoapi.rabbitmq_listener.asyncio.run_coroutine_threadsafe", + "indigoapi.queue.rabbitmq.asyncio.run_coroutine_threadsafe", lambda coro, event_loop: None, ) frame = SimpleNamespace(body="not-a-json") @@ -141,7 +141,7 @@ class BadFrame: def fake_error(msg): recorded.append(msg) - monkeypatch.setattr("indigoapi.rabbitmq_listener.logger.error", fake_error) + monkeypatch.setattr("indigoapi.queue.rabbitmq.logger.error", fake_error) listener.on_message(BadFrame()) assert recorded diff --git a/tests/test_registry.py b/tests/test_registry.py index 1c16cac..ba62cee 100644 --- a/tests/test_registry.py +++ b/tests/test_registry.py @@ -3,8 +3,8 @@ import pytest -from indigoapi.analyses.decorator import analysis -from indigoapi.analyses.registry import ( +from indigoapi.analysis_core.decorator import analysis +from indigoapi.analysis_core.registry import ( ANALYSIS_REGISTRY, get_analysis, register_analysis,