Remove a load more /names/
This commit is contained in:
parent
e7f669cb56
commit
9ef417971f
15 changed files with 39 additions and 41 deletions
|
|
@ -32,10 +32,10 @@ def camera_test_client(
|
||||||
if settings_folder is None:
|
if settings_folder is None:
|
||||||
settings_folder = tmpdir
|
settings_folder = tmpdir
|
||||||
server = lt.ThingServer(settings_folder=settings_folder)
|
server = lt.ThingServer(settings_folder=settings_folder)
|
||||||
server.add_thing(cam, "/camera/")
|
server.add_thing(cam, "camera")
|
||||||
|
|
||||||
with TestClient(server.app) as test_client:
|
with TestClient(server.app) as test_client:
|
||||||
client = lt.ThingClient.from_url("/camera/", client=test_client)
|
client = lt.ThingClient.from_url("camera", client=test_client)
|
||||||
yield client
|
yield client
|
||||||
del server
|
del server
|
||||||
del cam
|
del cam
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ def picamera_client(picamera_thing) -> lt.ThingClient:
|
||||||
This fixture:
|
This fixture:
|
||||||
|
|
||||||
* Sets up a ThingServer,
|
* Sets up a ThingServer,
|
||||||
* Registers a StreamingPiCamera2 instance at the "/camera/" endpoint
|
* Registers a StreamingPiCamera2 instance at the "camera" endpoint
|
||||||
* Provides a ThingClient for interacting with it during tests.
|
* Provides a ThingClient for interacting with it during tests.
|
||||||
"""
|
"""
|
||||||
with camera_test_client(cam=picamera_thing) as picamera_client:
|
with camera_test_client(cam=picamera_thing) as picamera_client:
|
||||||
|
|
|
||||||
|
|
@ -63,11 +63,11 @@ def customise_server(
|
||||||
def _get_scans_dir(config: dict) -> Optional[str]:
|
def _get_scans_dir(config: dict) -> Optional[str]:
|
||||||
"""Read the config and return the scans directory.
|
"""Read the config and return the scans directory.
|
||||||
|
|
||||||
Return is None if there is no /smart_scan/ thing loaded.
|
Return is None if there is no smart_scan thing loaded.
|
||||||
"""
|
"""
|
||||||
if "/smart_scan/" in config["things"]:
|
if "smart_scan" in config["things"]:
|
||||||
try:
|
try:
|
||||||
return config["things"]["/smart_scan/"]["kwargs"]["scans_folder"]
|
return config["things"]["smart_scan"]["kwargs"]["scans_folder"]
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
msg = "Configuration error: smart scan should have scans_folder kwarg set"
|
msg = "Configuration error: smart scan should have scans_folder kwarg set"
|
||||||
raise RuntimeError(msg) from e
|
raise RuntimeError(msg) from e
|
||||||
|
|
@ -96,7 +96,7 @@ def serve_from_cli(argv: Optional[list[str]] = None) -> None:
|
||||||
def shutdown_call() -> None:
|
def shutdown_call() -> None:
|
||||||
try:
|
try:
|
||||||
# Kill any mjpeg streams so that StreamingResponses close.
|
# Kill any mjpeg streams so that StreamingResponses close.
|
||||||
server.things["/camera/"].kill_mjpeg_streams()
|
server.things["camera"].kill_mjpeg_streams()
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
# Catch anything and log as it is essential that this
|
# Catch anything and log as it is essential that this
|
||||||
# function cannot raise an unhandled exception or Uvicorn
|
# function cannot raise an unhandled exception or Uvicorn
|
||||||
|
|
|
||||||
|
|
@ -731,7 +731,7 @@ class BaseCamera(lt.Thing):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
CameraDependency = lt.deps.direct_thing_client_dependency(BaseCamera, "/camera/")
|
CameraDependency = lt.deps.direct_thing_client_dependency(BaseCamera, "camera")
|
||||||
RawCameraDependency = lt.deps.raw_thing_dependency(BaseCamera)
|
RawCameraDependency = lt.deps.raw_thing_dependency(BaseCamera)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,9 @@ T = TypeVar("T")
|
||||||
P = ParamSpec("P")
|
P = ParamSpec("P")
|
||||||
|
|
||||||
CSMDep = lt.deps.direct_thing_client_dependency(
|
CSMDep = lt.deps.direct_thing_client_dependency(
|
||||||
CameraStageMapper, "/camera_stage_mapping/"
|
CameraStageMapper, "camera_stage_mapping"
|
||||||
)
|
)
|
||||||
AutofocusDep = lt.deps.direct_thing_client_dependency(AutofocusThing, "/autofocus/")
|
AutofocusDep = lt.deps.direct_thing_client_dependency(AutofocusThing, "autofocus")
|
||||||
|
|
||||||
|
|
||||||
class ScanListInfo(BaseModel):
|
class ScanListInfo(BaseModel):
|
||||||
|
|
|
||||||
|
|
@ -228,4 +228,4 @@ class BaseStage(lt.Thing):
|
||||||
self.move_absolute(cancel=cancel, x=xyz_pos[0], y=xyz_pos[1], z=xyz_pos[2])
|
self.move_absolute(cancel=cancel, x=xyz_pos[0], y=xyz_pos[1], z=xyz_pos[2])
|
||||||
|
|
||||||
|
|
||||||
StageDependency = lt.deps.direct_thing_client_dependency(BaseStage, "/stage/")
|
StageDependency = lt.deps.direct_thing_client_dependency(BaseStage, "stage")
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,9 @@ from .camera_stage_mapping import CameraStageMapper
|
||||||
from .stage import StageDependency as StageDep
|
from .stage import StageDependency as StageDep
|
||||||
|
|
||||||
CSMDep = lt.deps.direct_thing_client_dependency(
|
CSMDep = lt.deps.direct_thing_client_dependency(
|
||||||
CameraStageMapper, "/camera_stage_mapping/"
|
CameraStageMapper, "camera_stage_mapping"
|
||||||
)
|
)
|
||||||
AutofocusDep = lt.deps.direct_thing_client_dependency(AutofocusThing, "/autofocus/")
|
AutofocusDep = lt.deps.direct_thing_client_dependency(AutofocusThing, "autofocus")
|
||||||
|
|
||||||
## Size of movement in percentage of field of view
|
## Size of movement in percentage of field of view
|
||||||
SMALL_STEP = 20
|
SMALL_STEP = 20
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,8 @@ def action_button_for(action: Callable[..., Any], **kwargs: Any) -> ActionButton
|
||||||
:param kwargs: Any attribute of `ActionButton` except for ``thing`` or ``action``.
|
:param kwargs: Any attribute of `ActionButton` except for ``thing`` or ``action``.
|
||||||
"""
|
"""
|
||||||
thing = action.args[0]
|
thing = action.args[0]
|
||||||
thing_path = thing.path.strip("/")
|
|
||||||
action_name = action.func.__name__
|
action_name = action.func.__name__
|
||||||
return ActionButton(thing=thing_path, action=action_name, **kwargs)
|
return ActionButton(thing=thing.name, action=action_name, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class PropertyControl(BaseModel):
|
class PropertyControl(BaseModel):
|
||||||
|
|
@ -94,7 +93,6 @@ def property_control_for(
|
||||||
:param kwargs: Any attribute of `PropertyControl` except for ``thing`` or
|
:param kwargs: Any attribute of `PropertyControl` except for ``thing`` or
|
||||||
``property_name``. If label is not set here it will be the property name.
|
``property_name``. If label is not set here it will be the property name.
|
||||||
"""
|
"""
|
||||||
thing_path = thing.path.strip("/")
|
|
||||||
if "label" not in kwargs:
|
if "label" not in kwargs:
|
||||||
kwargs["label"] = property_name
|
kwargs["label"] = property_name
|
||||||
return PropertyControl(thing=thing_path, property_name=property_name, **kwargs)
|
return PropertyControl(thing=thing.name, property_name=property_name, **kwargs)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ def camera_server(camera: SimulatedCamera) -> lt.ThingClient:
|
||||||
"""
|
"""
|
||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
server = lt.ThingServer(settings_folder=tmpdir)
|
server = lt.ThingServer(settings_folder=tmpdir)
|
||||||
server.add_thing(camera, "/camera/")
|
server.add_thing(camera, "camera")
|
||||||
with TestClient(server.app):
|
with TestClient(server.app):
|
||||||
yield server
|
yield server
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,12 +35,12 @@ def thing_server():
|
||||||
SimulatedCamera(
|
SimulatedCamera(
|
||||||
shape=(240, 320, 3), canvas_shape=(1000, 1500, 3), frame_interval=0.01
|
shape=(240, 320, 3), canvas_shape=(1000, 1500, 3), frame_interval=0.01
|
||||||
),
|
),
|
||||||
"/camera/",
|
"camera",
|
||||||
)
|
)
|
||||||
server.add_thing(DummyStage(step_time=0.000001), "/stage/")
|
server.add_thing(DummyStage(step_time=0.000001), "stage")
|
||||||
server.add_thing(AutofocusThing(), "/autofocus/")
|
server.add_thing(AutofocusThing(), "autofocus")
|
||||||
server.add_thing(CameraStageMapper(), "/camera_stage_mapping/")
|
server.add_thing(CameraStageMapper(), "camera_stage_mapping")
|
||||||
assert os.path.exists(os.path.join(temp_folder.name, "camera/"))
|
assert os.path.exists(os.path.join(temp_folder.name, "camera"))
|
||||||
# Note: yield is important. If return is used the temp folder gets deleted
|
# Note: yield is important. If return is used the temp folder gets deleted
|
||||||
# before the test runs. Silence PT022 as ruff doesn't think yield is needed.
|
# before the test runs. Silence PT022 as ruff doesn't think yield is needed.
|
||||||
yield server # noqa: PT022
|
yield server # noqa: PT022
|
||||||
|
|
@ -60,7 +60,7 @@ def slower_client(thing_server):
|
||||||
The step time for the stage is 100 microseconds rather than
|
The step time for the stage is 100 microseconds rather than
|
||||||
1 microsecond.
|
1 microsecond.
|
||||||
"""
|
"""
|
||||||
thing_server.things["/stage/"].step_time = 0.0001
|
thing_server.things["stage"].step_time = 0.0001
|
||||||
with TestClient(thing_server.app) as client:
|
with TestClient(thing_server.app) as client:
|
||||||
yield client
|
yield client
|
||||||
|
|
||||||
|
|
@ -68,31 +68,31 @@ def slower_client(thing_server):
|
||||||
def test_autofocus(slower_client):
|
def test_autofocus(slower_client):
|
||||||
"""Test Fast Autofocus can run doesn't raise an exception."""
|
"""Test Fast Autofocus can run doesn't raise an exception."""
|
||||||
client = slower_client
|
client = slower_client
|
||||||
autofocus = lt.ThingClient.from_url("/autofocus/", client)
|
autofocus = lt.ThingClient.from_url("autofocus", client)
|
||||||
_ = autofocus.fast_autofocus()
|
_ = autofocus.fast_autofocus()
|
||||||
|
|
||||||
|
|
||||||
def test_grab_jpeg(client):
|
def test_grab_jpeg(client):
|
||||||
"""Check that grab_jpeg returns a blob that can be opened."""
|
"""Check that grab_jpeg returns a blob that can be opened."""
|
||||||
camera = lt.ThingClient.from_url("/camera/", client)
|
camera = lt.ThingClient.from_url("camera", client)
|
||||||
blob = camera.grab_jpeg()
|
blob = camera.grab_jpeg()
|
||||||
_image = Image.open(blob.open())
|
_image = Image.open(blob.open())
|
||||||
|
|
||||||
|
|
||||||
def test_capture_jpeg_metadata(client):
|
def test_capture_jpeg_metadata(client):
|
||||||
"""Check that the position is encoded into the image metadata."""
|
"""Check that the position is encoded into the image metadata."""
|
||||||
camera = lt.ThingClient.from_url("/camera/", client)
|
camera = lt.ThingClient.from_url("camera", client)
|
||||||
blob = camera.capture_jpeg()
|
blob = camera.capture_jpeg()
|
||||||
image = Image.open(blob.open())
|
image = Image.open(blob.open())
|
||||||
exif_dict = piexif.load(image.info["exif"])
|
exif_dict = piexif.load(image.info["exif"])
|
||||||
encoded_metadata = exif_dict["Exif"][piexif.ExifIFD.UserComment]
|
encoded_metadata = exif_dict["Exif"][piexif.ExifIFD.UserComment]
|
||||||
metadata = json.loads(encoded_metadata)
|
metadata = json.loads(encoded_metadata)
|
||||||
assert "position" in metadata["/stage/"]
|
assert "position" in metadata["stage"]
|
||||||
|
|
||||||
|
|
||||||
def test_stage(client):
|
def test_stage(client):
|
||||||
"""Test moving th stage forwards and backwards."""
|
"""Test moving th stage forwards and backwards."""
|
||||||
stage = lt.ThingClient.from_url("/stage/", client)
|
stage = lt.ThingClient.from_url("stage", client)
|
||||||
start = stage.position
|
start = stage.position
|
||||||
move = {"x": 1, "y": 2, "z": 3}
|
move = {"x": 1, "y": 2, "z": 3}
|
||||||
stage.move_relative(**move)
|
stage.move_relative(**move)
|
||||||
|
|
@ -107,14 +107,14 @@ def test_stage(client):
|
||||||
|
|
||||||
def test_capture_array(client):
|
def test_capture_array(client):
|
||||||
"""Capture array from simulation and check the size is as expected."""
|
"""Capture array from simulation and check the size is as expected."""
|
||||||
camera = lt.ThingClient.from_url("/camera/", client)
|
camera = lt.ThingClient.from_url("camera", client)
|
||||||
array = np.asarray(camera.capture_array())
|
array = np.asarray(camera.capture_array())
|
||||||
assert array.shape == (240, 320, 3)
|
assert array.shape == (240, 320, 3)
|
||||||
|
|
||||||
|
|
||||||
def test_camera_stage_mapping_calibration(client):
|
def test_camera_stage_mapping_calibration(client):
|
||||||
"""Check that camera stage mapping can run without an exception."""
|
"""Check that camera stage mapping can run without an exception."""
|
||||||
camera = lt.ThingClient.from_url("/camera/", client)
|
camera = lt.ThingClient.from_url("camera", client)
|
||||||
camera.settling_time = 0
|
camera.settling_time = 0
|
||||||
camera_stage_mapping = lt.ThingClient.from_url("/camera_stage_mapping/", client)
|
camera_stage_mapping = lt.ThingClient.from_url("camera_stage_mapping", client)
|
||||||
camera_stage_mapping.calibrate_xy()
|
camera_stage_mapping.calibrate_xy()
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ def test_v2_endpoints(mocker):
|
||||||
"""Check that the expected v2 endpoints are added."""
|
"""Check that the expected v2 endpoints are added."""
|
||||||
mock_server = mocker.Mock()
|
mock_server = mocker.Mock()
|
||||||
# Mock the camera thing to mocke the lores_mjpeg stream get_frame()
|
# Mock the camera thing to mocke the lores_mjpeg stream get_frame()
|
||||||
mock_server.things = {"/camera/": mocker.Mock()}
|
mock_server.things = {"camera": mocker.Mock()}
|
||||||
mock_server.things["/camera/"].lores_mjpeg_stream.grab_frame = mocker.AsyncMock(
|
mock_server.things["camera"].lores_mjpeg_stream.grab_frame = mocker.AsyncMock(
|
||||||
return_value="Mock Frame"
|
return_value="Mock Frame"
|
||||||
)
|
)
|
||||||
mock_app = mock_server.app
|
mock_app = mock_server.app
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ def test_get_scans_dir_no_smart_scan():
|
||||||
with open(FULL_CONFIG, "r", encoding="utf-8") as f_obj:
|
with open(FULL_CONFIG, "r", encoding="utf-8") as f_obj:
|
||||||
config_dict = json.load(f_obj)
|
config_dict = json.load(f_obj)
|
||||||
# Delete smart scan
|
# Delete smart scan
|
||||||
del config_dict["things"]["/smart_scan/"]
|
del config_dict["things"]["smart_scan"]
|
||||||
# No SmartScanThing, should return None
|
# No SmartScanThing, should return None
|
||||||
assert ofm_server._get_scans_dir(config_dict) is None
|
assert ofm_server._get_scans_dir(config_dict) is None
|
||||||
|
|
||||||
|
|
@ -116,14 +116,14 @@ def test_get_scans_dir_bad_smart_scan_config():
|
||||||
# Copy the dictionary
|
# Copy the dictionary
|
||||||
broken_config = deepcopy(config_dict)
|
broken_config = deepcopy(config_dict)
|
||||||
# Delete all the smart scan kwargs
|
# Delete all the smart scan kwargs
|
||||||
del broken_config["things"]["/smart_scan/"]["kwargs"]
|
del broken_config["things"]["smart_scan"]["kwargs"]
|
||||||
# Creates an Error
|
# Creates an Error
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
ofm_server._get_scans_dir(broken_config)
|
ofm_server._get_scans_dir(broken_config)
|
||||||
|
|
||||||
# Same thing should happen if just the scans_folder key is deleted
|
# Same thing should happen if just the scans_folder key is deleted
|
||||||
broken_config = deepcopy(config_dict)
|
broken_config = deepcopy(config_dict)
|
||||||
del broken_config["things"]["/smart_scan/"]["kwargs"]
|
del broken_config["things"]["smart_scan"]["kwargs"]
|
||||||
# Creates an Error
|
# Creates an Error
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
ofm_server._get_scans_dir(broken_config)
|
ofm_server._get_scans_dir(broken_config)
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,7 @@ def autofocus_thing():
|
||||||
autofocus_thing = AutofocusThing()
|
autofocus_thing = AutofocusThing()
|
||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
server = lt.ThingServer(settings_folder=tmpdir)
|
server = lt.ThingServer(settings_folder=tmpdir)
|
||||||
server.add_thing(autofocus_thing, "/autofocus/")
|
server.add_thing(autofocus_thing, "autofocus")
|
||||||
with TestClient(server.app):
|
with TestClient(server.app):
|
||||||
yield autofocus_thing
|
yield autofocus_thing
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ def thing_server(dummy_stage):
|
||||||
"""Yield a server with a very basic configuration."""
|
"""Yield a server with a very basic configuration."""
|
||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
server = lt.ThingServer(settings_folder=tmpdir)
|
server = lt.ThingServer(settings_folder=tmpdir)
|
||||||
server.add_thing(dummy_stage, "/stage/")
|
server.add_thing(dummy_stage, "stage")
|
||||||
yield server
|
yield server
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ def thing_server(dummy_stage):
|
||||||
def stage_client(thing_server):
|
def stage_client(thing_server):
|
||||||
"""Yield a labthings ThingClient for the stage."""
|
"""Yield a labthings ThingClient for the stage."""
|
||||||
with TestClient(thing_server.app) as test_client:
|
with TestClient(thing_server.app) as test_client:
|
||||||
yield lt.ThingClient.from_url("/stage/", client=test_client)
|
yield lt.ThingClient.from_url("stage", client=test_client)
|
||||||
|
|
||||||
|
|
||||||
def test_override_base_movement():
|
def test_override_base_movement():
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ def rom_thing(example_rom_data) -> stage_measure.RangeofMotionThing:
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
server = lt.ThingServer(settings_folder=tmpdir)
|
server = lt.ThingServer(settings_folder=tmpdir)
|
||||||
server.add_thing(rom_thing, "/rom_thing/")
|
server.add_thing(rom_thing, "rom_thing")
|
||||||
with TestClient(server.app):
|
with TestClient(server.app):
|
||||||
yield rom_thing
|
yield rom_thing
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue