Skip to content
Snippets Groups Projects
Commit 6ce61a64 authored by Christopher Randolph Rhodes's avatar Christopher Randolph Rhodes
Browse files

Can now restart session by API with new data root

parent 95c5c9fd
No related branches found
No related tags found
No related merge requests found
......@@ -19,20 +19,16 @@ def read_root():
return {'success': True}
@app.put('/bounce_back')
def read_root(par1=None, par2=None):
def list_bounce_back(par1=None, par2=None):
return {'success': True, 'params': {'par1': par1, 'par2': par2}}
@app.get('/paths')
def list_session_paths():
pass
@app.put('/paths/{path_id}')
def set_path_id(path_id: str, abs_path: str):
pass
return session.get_paths()
@app.get('/restart')
def restart_session() -> dict:
session.restart()
def restart_session(root: str = None) -> dict:
session.restart(root=root)
return session.describe_loaded_models()
@app.get('/models')
......@@ -68,7 +64,7 @@ def infer_img(model_id: str, input_filename: str, channel: int = None) -> dict:
status_code=409,
detail=f'Model {model_id} has not been loaded'
)
inpath = session.inbound.path / input_filename
inpath = session.paths['inbound_images'] / input_filename
if not inpath.exists():
raise HTTPException(
status_code=404,
......@@ -77,7 +73,7 @@ def infer_img(model_id: str, input_filename: str, channel: int = None) -> dict:
record = infer_image_to_image(
inpath,
session.models[model_id]['object'],
session.outbound.path,
session.paths['outbound_images'],
channel=channel,
)
session.record_workflow_run(record)
......
from pathlib import Path
root = Path('c:/Users/rhodes/projects/proj0015-model-server/resources')
paths = {
'logs': root / 'logs' / 'session',
'inbound_images': root / 'images' / 'inbound',
'outbound_images': root / 'images' / 'outbound',
'ilastik_projects': root / 'ilastik',
}
# paths = {
# 'logs': root / 'logs' / 'session',
# 'inbound_images': root / 'images' / 'inbound',
# 'outbound_images': root / 'images' / 'outbound',
# 'ilastik_projects': root / 'ilastik',
# }
for gk in paths.keys():
paths[gk].mkdir(parents=True, exist_ok=True)
# TODO: consider configuring paths via API, and this just becomes a HTTP client script
\ No newline at end of file
subdirectories = {
'logs': 'logs/session',
'inbound_images': 'images/inbound',
'outbound_images': 'images/outbound',
'ilastik_projects': 'ilastik',
}
\ No newline at end of file
......@@ -5,7 +5,7 @@ from pathlib import Path
from time import strftime, localtime
from typing import Dict
from conf.defaults import paths
import conf.defaults
from model_server.model import Model
from model_server.share import SharedImageDirectory
from model_server.workflow import WorkflowRunRecord
......@@ -17,25 +17,51 @@ class Session(object):
"""
Singleton class for a server session that persists data between API calls
"""
inbound = SharedImageDirectory(paths['inbound_images'])
outbound = SharedImageDirectory(paths['outbound_images'])
where_records = paths['logs']
# inbound = SharedImageDirectory(conf.defaults.paths['inbound_images'])
# outbound = SharedImageDirectory(conf.defaults.paths['outbound_images'])
# where_records = conf.defaults.paths['logs']
def __new__(cls):
if not hasattr(cls, 'instance'):
cls.instance = super(Session, cls).__new__(cls)
return cls.instance
def __init__(self):
def __init__(self, root: str = None):
print('Initializing session')
self.models = {} # model_id : model object
self.manifest = [] # paths to data as well as other metadata from each inference run
self.session_id = self.create_session_id(self.where_records)
self.session_log = self.where_records / f'{self.session_id}.log'
self.paths = self.make_paths(root)
self.session_id = self.create_session_id(self.paths['logs'])
self.session_log = self.paths['logs'] / f'{self.session_id}.log'
self.log_event('Initialized session')
self.manifest_json = self.where_records / f'{self.session_id}-manifest.json'
self.manifest_json = self.paths['logs'] / f'{self.session_id}-manifest.json'
open(self.manifest_json, 'w').close() # instantiate empty json file
def get_paths(self):
return self.paths
@staticmethod
def make_paths(root: str = None) -> dict:
"""
Set paths where images, logs, etc. are located in this session
:param root: absolute path to top-level directory
:return: dictionary of session paths
"""
paths = {}
if root is None:
root_path = Path(conf.defaults.root)
else:
root_path = Path(root)
sid = Session.create_session_id(root_path)
for pk in ['inbound_images', 'outbound_images', 'logs']:
pa = root_path / sid / conf.defaults.subdirectories[pk]
paths[pk] = pa
try:
pa.mkdir(parents=True, exist_ok=True)
except Exception:
raise CouldNotCreateDirectory(f'Could not create directory: {pa}')
return paths
@staticmethod
def create_session_id(look_where: Path) -> str:
"""
......@@ -98,8 +124,8 @@ class Session(object):
for k in self.models.keys()
}
def restart(self):
self.__init__()
def restart(self, **kwargs):
self.__init__(**kwargs)
class Error(Exception):
pass
......@@ -108,4 +134,7 @@ class InferenceRecordError(Error):
pass
class CouldNotInstantiateModelError(Error):
pass
class CouldNotCreateDirectory(Error):
pass
\ No newline at end of file
from multiprocessing import Process
from pathlib import Path
import requests
import unittest
......@@ -20,18 +21,6 @@ class TestServerBaseClass(unittest.TestCase):
self.uri = f'http://{host}:{port}/'
self.server_process.start()
@staticmethod
def copy_input_file_to_server():
from shutil import copyfile
from conf.defaults import paths
outpath = paths['inbound_images'] / czifile['filename']
copyfile(
czifile['path'],
outpath
)
def tearDown(self) -> None:
self.server_process.terminate()
......@@ -49,8 +38,15 @@ class TestApiFromAutomatedClient(TestServerBaseClass):
def test_default_session_paths(self):
import conf.defaults
resp = requests.get(self.uri + 'paths')
for p in ['inbound', 'outbound', 'logs']:
self.assertEqual(resp.json()['paths'][p], conf.defaults.paths[p])
conf_root = conf.defaults.root
for p in ['inbound_images', 'outbound_images', 'logs']:
self.assertTrue(resp.json()[p].startswith(conf_root.__str__()))
suffix = Path(conf.defaults.subdirectories[p]).__str__()
self.assertTrue(resp.json()[p].endswith(suffix))
def test_restart_with_new_root_directory(self):
pass
# TODO: implement
def test_list_empty_loaded_models(self):
resp = requests.get(self.uri + 'models')
......@@ -93,6 +89,17 @@ class TestApiFromAutomatedClient(TestServerBaseClass):
)
self.assertEqual(resp.status_code, 409, resp.content.decode())
def copy_input_file_to_server(self):
from shutil import copyfile
resp = requests.get(self.uri + 'paths')
pa = resp.json()['inbound_images']
outpath = Path(pa) / czifile['filename']
copyfile(
czifile['path'],
outpath
)
def test_i2i_dummy_inference_by_api(self):
model_id = self.test_load_dummy_model()
self.copy_input_file_to_server()
......
......@@ -14,6 +14,17 @@ class TestGetSessionObject(unittest.TestCase):
self.assertTrue(exists(sesh.session_log), 'Session did not create a log file in the correct place')
self.assertTrue(exists(sesh.manifest_json), 'Session did not create a manifest JSON file in the correct place')
def test_can_change_session_root(self):
from conf.defaults import root
sesh = Session()
old_paths = sesh.get_paths()
newroot = root / 'subdir'
sesh.restart(root=newroot)
new_paths = sesh.get_paths()
for k in old_paths.keys():
self.assertTrue(new_paths[k].__str__().startswith(newroot.__str__()))
def test_restart_session(self):
sesh = Session()
logfile1 = sesh.session_log
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment