Skip to content

Commit

Permalink
Merge pull request #344 from AllenNeuralDynamics/release-v0.19.2
Browse files Browse the repository at this point in the history
Release v0.19.2
  • Loading branch information
jtyoung84 authored Feb 10, 2025
2 parents 4dc48eb + 7e09e65 commit e71626b
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/aind_metadata_service/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""REST service to retrieve metadata from databases."""

__version__ = "0.19.1"
__version__ = "0.19.2"
12 changes: 8 additions & 4 deletions src/aind_metadata_service/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,20 @@ async def retrieve_bergamo_session(job_settings: BergamoJobSettings):


@app.get("/instrument/{instrument_id}")
async def retrieve_instrument(instrument_id):
async def retrieve_instrument(instrument_id, partial_match=False):
"""Retrieves instrument from slims"""
model_response = slims_client.get_instrument_model_response(instrument_id)
model_response = slims_client.get_instrument_model_response(
instrument_id, partial_match=partial_match
)
return model_response.map_to_json_response(validate=False)


@app.get("/rig/{rig_id}")
async def retrieve_rig(rig_id):
async def retrieve_rig(rig_id, partial_match=False):
"""Retrieves rig from slims"""
model_response = slims_client.get_rig_model_response(rig_id)
model_response = slims_client.get_rig_model_response(
rig_id, partial_match=partial_match
)
return model_response.map_to_json_response(validate=False)


Expand Down
47 changes: 37 additions & 10 deletions src/aind_metadata_service/slims/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from pydantic import Extra, Field, SecretStr
from pydantic_settings import BaseSettings
from requests.models import Response
from slims import criteria
from slims.criteria import equals

from aind_metadata_service.client import StatusCodes
Expand Down Expand Up @@ -55,16 +56,29 @@ def _is_json_file(file: Response) -> bool:
"""Checks whether file is a json."""
return file.headers.get("Content-Type", "") == "application/json"

def get_instrument_model_response(self, input_id) -> ModelResponse:
def get_instrument_model_response(
self, input_id: str, partial_match: bool = False
) -> ModelResponse:
"""
Fetches a response from SLIMS, extracts Instrument models from the
response and creates a ModelResponse with said models.
"""
try:
inst = self.client.fetch_model(SlimsInstrumentRdrc, name=input_id)
attachment = self.client.fetch_attachment(
inst, equals("name", input_id)
)
if partial_match:
inst = self.client.fetch_model(
SlimsInstrumentRdrc,
criteria.contains("name", input_id),
)
attachment = self.client.fetch_attachment(
inst,
)
else:
inst = self.client.fetch_model(
SlimsInstrumentRdrc, name=input_id
)
attachment = self.client.fetch_attachment(
inst, equals("name", input_id)
)
if attachment:
attachment_response = self.client.fetch_attachment_content(
attachment
Expand All @@ -91,16 +105,29 @@ def get_instrument_model_response(self, input_id) -> ModelResponse:
logging.error(repr(e))
return ModelResponse.internal_server_error_response()

def get_rig_model_response(self, input_id) -> ModelResponse:
def get_rig_model_response(
self, input_id: str, partial_match: bool = False
) -> ModelResponse:
"""
Fetches a response from SLIMS, extracts Rig models from the
response and creates a ModelResponse with said models.
"""
try:
inst = self.client.fetch_model(SlimsInstrumentRdrc, name=input_id)
attachment = self.client.fetch_attachment(
inst, equals("name", input_id)
)
if partial_match:
inst = self.client.fetch_model(
SlimsInstrumentRdrc,
criteria.contains("name", input_id),
)
attachment = self.client.fetch_attachment(
inst,
)
else:
inst = self.client.fetch_model(
SlimsInstrumentRdrc, name=input_id
)
attachment = self.client.fetch_attachment(
inst, equals("name", input_id)
)
if attachment:
attachment_response = self.client.fetch_attachment_content(
attachment
Expand Down
2 changes: 0 additions & 2 deletions src/aind_metadata_service/smartsheet/funding/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,6 @@ def get_project_names(self) -> JSONResponse:
if project_name is not None and subproject_name is None:
project_names.add(project_name)
elif project_name is not None and subproject_name is not None:
# Support legacy input.
project_names.add(project_name)
project_names.add(f"{project_name} - {subproject_name}")
return JSONResponse(
status_code=200,
Expand Down
58 changes: 58 additions & 0 deletions tests/slims/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,37 @@ def test_get_instrument_model_response_success(self, mock_is_json_file):
SlimsInstrumentRdrc, name="test_id"
)

@patch(
"aind_metadata_service.slims.client.SlimsHandler._is_json_file",
)
@patch("slims.criteria.contains")
def test_get_instrument_model_response_success_partial_match(
self, mock_contains: MagicMock, mock_is_json_file: MagicMock
):
"""Test successful response from get_instrument_model_response when
partial_match is set to True"""
mock_inst = MagicMock()
mock_is_json_file.return_value = True
self.mock_client.fetch_model.return_value = mock_inst
mock_attachment = MagicMock()
self.mock_client.fetch_attachment.return_value = mock_attachment
mock_response = MagicMock(spec=Response)
mock_response.status_code = 200
mock_response.json.return_value = {}
self.mock_client.fetch_attachment_content.return_value = mock_response

with patch(
"aind_data_schema.core.instrument.Instrument.model_construct"
) as mock_construct:
mock_construct.return_value = MagicMock(spec=Instrument)
response = self.handler.get_instrument_model_response(
"test_id", partial_match=True
)

self.assertEqual(response.status_code, StatusCodes.DB_RESPONDED)
mock_construct.assert_called_once_with(**mock_response.json())
mock_contains.assert_called_once_with("name", "test_id")

def test_get_instrument_model_response_invalid_response(self):
"""Test response when the content is not valid response."""
mock_inst = MagicMock()
Expand Down Expand Up @@ -193,6 +224,33 @@ def test_get_rig_model_response_success(self):
SlimsInstrumentRdrc, name="test_id"
)

@patch("slims.criteria.contains")
def test_get_rig_model_response_success_partial_match(
self, mock_contains: MagicMock
):
"""Test successful response from get_rig_model_response when
partial_match is set to True."""
mock_inst = MagicMock()
self.mock_client.fetch_model.return_value = mock_inst
mock_attachment = MagicMock()
self.mock_client.fetch_attachment.return_value = mock_attachment
mock_response = MagicMock(spec=Response)
mock_response.status_code = 200
mock_response.json.return_value = {}
self.mock_client.fetch_attachment_content.return_value = mock_response

with patch(
"aind_data_schema.core.rig.Rig.model_construct"
) as mock_construct:
mock_construct.return_value = MagicMock(spec=Rig)
response = self.handler.get_rig_model_response(
"test_id", partial_match=True
)

self.assertEqual(response.status_code, StatusCodes.DB_RESPONDED)
mock_construct.assert_called_once_with(**mock_response.json())
mock_contains.assert_called_once_with("name", "test_id")

def test_get_rig_model_response_not_found(self):
"""Test when SlimsRecordNotFound is raised."""
self.mock_client.fetch_model.side_effect = SlimsRecordNotFound
Expand Down
1 change: 0 additions & 1 deletion tests/smartsheet/test_funding.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ def test_get_project_names_success(self, mock_get_sheet: MagicMock):
expected_response = {
"message": "Success",
"data": [
"Discovery-Neuromodulator circuit dynamics during " "foraging",
(
"Discovery-Neuromodulator circuit dynamics during foraging"
" - Subproject 1 Electrophysiological Recordings from NM "
Expand Down

0 comments on commit e71626b

Please sign in to comment.