diff --git a/svlt-core/requirements.yml b/svlt-core/requirements.yml index 6d77a684b2e22a2e6557cdf5942822221453002a..dd0e6a21006fd99bb41d9c50f3ea8e6ecadf5a55 100644 --- a/svlt-core/requirements.yml +++ b/svlt-core/requirements.yml @@ -11,9 +11,8 @@ dependencies: - pandas - pillow - pip - - pydantic=1.10.* + - pydantic=2.* - python=3.9.* - - pytorch=1.* - scikit-image>=0.21.0 - tifffile - uvicorn>=0.23.0 diff --git a/svlt-core/src/svlt/api.py b/svlt-core/src/svlt/api.py index f257069f5ffb8ede27d8262a6d4ef98180f5a6b0..ff7768b8399ce79759c5867b552851a5ac671ba6 100644 --- a/svlt-core/src/svlt/api.py +++ b/svlt-core/src/svlt/api.py @@ -7,7 +7,7 @@ from pydantic import BaseModel, Field from .accessors import generate_file_accessor, generate_multiposition_file_accessors from .models import BinaryThresholdSegmentationModel -from .pipelines.common import PipelineRecord +from .pipelines.common import PipelineParams, PipelineRecord from .session import session, AccessorIdError, InvalidPathError, WriteAccessorError app = FastAPI(debug=True) @@ -185,12 +185,12 @@ def read_multiposition_from_file(filename: str, lazy: bool = False) -> List[str] class TaskInfo(BaseModel): module: str - params: dict + params: PipelineParams func_str: str status: str target: Union[str, None] error: Union[str, None] - result: Union[Dict, None] + result: Union[PipelineRecord, None] @app.put('/tasks/run_all') def run_all_tasks(write_all: bool = False) -> List[PipelineRecord]: diff --git a/svlt-core/src/svlt/conf/testing.py b/svlt-core/src/svlt/conf/testing.py index da11763dcf2042970e0bf6b1e62af50cfd27d1dd..a1e233acf1059cbec0c0520013e63f41275984d2 100644 --- a/svlt-core/src/svlt/conf/testing.py +++ b/svlt-core/src/svlt/conf/testing.py @@ -4,7 +4,10 @@ import unittest from math import floor from multiprocessing import Process from pathlib import Path +import requests +from requests.adapters import HTTPAdapter from shutil import copyfile +from urllib3 import Retry from fastapi import APIRouter import numpy as np @@ -98,8 +101,19 @@ class TestServerBaseClass(unittest.TestCase): daemon=True ) self.server_process.start() + sesh = requests.Session() + retries = Retry( + total=10, + backoff_factor=0.5, + ) + sesh.mount('http://', requests.adapters.HTTPAdapter(max_retries=retries)) + resp = sesh.get(f'http://{host}:{int(port):04d}/' + 'status') + assert resp.status_code == 200 + self.client = HttpClient(host=host, port=port) + + def assertGetSuccess(self, endpoint): resp = self.client.get(endpoint) self.assertEqual(resp.status_code, 200, resp.text) diff --git a/svlt-core/src/svlt/pipelines/common.py b/svlt-core/src/svlt/pipelines/common.py index 63ffb9255a87f9a2bb5accc4620a936f9c24a247..c4638266c4e7677d5563794600117fedd8038d82 100644 --- a/svlt-core/src/svlt/pipelines/common.py +++ b/svlt-core/src/svlt/pipelines/common.py @@ -4,7 +4,7 @@ from time import perf_counter from typing import Dict, List, Union from fastapi import HTTPException -from pydantic import BaseModel, Field, root_validator +from pydantic import ConfigDict, BaseModel, Field, model_validator from ..accessors import GenericImageDataAccessor, InMemoryDataAccessor from ..session import session, AccessorIdError @@ -15,31 +15,32 @@ class PipelineParams(BaseModel): keep_interm: bool = Field(False, description='Keep accessors to intermediate images in session') api: bool = Field(True, description='Validate parameters against server session and map HTTP errors if True') calling_task_id: Union[str, None] = Field(None, description='ID of the task that calls pipeline function') + model_config = ConfigDict(protected_namespaces = ()) - @root_validator(pre=False) - def models_are_loaded(cls, dd): - for k, v in dd.items(): - if dd['api'] and k.endswith('model_id') and v is not None: + @model_validator(mode='after') + def models_are_loaded(self): + for k, v in self.model_dump().items(): + if self.api and k.endswith('model_id') and v is not None: if v not in session.describe_loaded_models().keys(): raise HTTPException(status_code=409, detail=f'Model with {k} = {v} has not been loaded') - return dd + return self - @root_validator(pre=False) - def accessors_are_loaded(cls, dd): - for k, v in dd.items(): - if dd['api'] and k.endswith('accessor_id'): + @model_validator(mode='after') + def accessors_are_loaded(self): + for k, v in self.model_dump().items(): + if self.api and k.endswith('accessor_id'): try: info = session.get_accessor_info(v) except AccessorIdError as e: raise HTTPException(status_code=409, detail=str(e)) if not session.is_accessor_loaded(v): raise HTTPException(status_code=409, detail=f'Accessor with {k} = {v} has not been loaded') - return dd + return self class PipelineRecord(BaseModel): output_accessor_id: str - interm_accessor_ids: Union[Dict[str, str], None] + interm_accessor_ids: Union[Dict[str, str], None] = None success: bool timer: dict diff --git a/svlt-ilastik/requirements.yml b/svlt-ilastik/requirements.yml index 17b48c72bea7451e62e98aad382a3899c3cc2335..8e0705392a16c1accf348ca1ce56628c996dd192 100644 --- a/svlt-ilastik/requirements.yml +++ b/svlt-ilastik/requirements.yml @@ -6,7 +6,7 @@ channels: dependencies: - czifile - fastapi>=0.101 - - ilastik=1.4.1b6 + - ilastik=1.4.1b23 - imagecodecs - matplotlib - nd2 @@ -14,10 +14,9 @@ dependencies: - pandas - pillow - pip - - protobuf ==4.25.3 - - pydantic=1.10.* + - pydantic=2.* - python=3.9.* - - pytorch=1.* + - pytorch - scikit-image>=0.21.0 - scikit-learn>=1.5.0 - tifffile diff --git a/svlt-pheno/requirements.yml b/svlt-pheno/requirements.yml index 5100aeeed4cf7f7bc6d6e9c6e4e970d279827a97..1b2acfb77f204b82fbf29638c873b82df8c88671 100644 --- a/svlt-pheno/requirements.yml +++ b/svlt-pheno/requirements.yml @@ -11,7 +11,7 @@ dependencies: - pandas - pillow - pip - - pydantic=1.10.* + - pydantic=2.* - python=3.9.* - scikit-image>=0.21.0 - scikit-learn>=1.5.0