Skip to content

Commit

Permalink
Merge pull request #113 from AllenNeuralDynamics/release-v0.17.0
Browse files Browse the repository at this point in the history
Release v0.17.0
  • Loading branch information
helen-m-lin authored Jan 6, 2025
2 parents a5d5c53 + ed281f5 commit 5d42bdf
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 32 deletions.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ source = ["aind_data_access_api", "tests"]
[tool.coverage.report]
exclude_lines = [
"if __name__ == .__main__.:",
"from",
"import",
"^from .* import .*",
"^import .*",
"pragma: no cover"
]
fail_under = 100
Expand Down
2 changes: 1 addition & 1 deletion src/aind_data_access_api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Init package"""

__version__ = "0.16.1"
__version__ = "0.17.0"
8 changes: 4 additions & 4 deletions src/aind_data_access_api/helpers/data_schema.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
"""Module for convenience functions for the data access API."""

import json

from aind_data_schema.core.quality_control import QualityControl

from aind_data_access_api.document_db import MetadataDbClient
from aind_data_access_api.helpers.docdb import (
get_field_by_id,
get_id_from_name,
)
from aind_data_schema.core.quality_control import QualityControl
import json


def get_quality_control_by_id(
Expand Down Expand Up @@ -56,8 +58,6 @@ def get_quality_control_by_name(
return invalid QualityControl as dict if True, by default False
"""
_id = get_id_from_name(client, name=name)
if not _id:
raise ValueError(f"No record found with name {name}")

return get_quality_control_by_id(
client, _id=_id, allow_invalid=allow_invalid
Expand Down
51 changes: 38 additions & 13 deletions src/aind_data_access_api/helpers/docdb.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""Utilities that go through the MetadataDBClient """

import logging
from typing import Optional

from aind_data_access_api.document_db import MetadataDbClient
import logging


def get_record_by_id(
Expand Down Expand Up @@ -83,9 +84,11 @@ def get_field_by_id(
def get_id_from_name(
client: MetadataDbClient,
name: str,
) -> Optional[str]:
) -> str:
"""
Get the _id of a record in DocDb from its name field.
Get the _id of a record in DocDb from its name field. If multiple share
the same name, only the first record is returned. If no record is found,
an exception is raised.
Parameters
----------
Expand All @@ -94,21 +97,43 @@ def get_id_from_name(
Returns
-------
Optional[str]
None if record does not exist. Otherwise, it will return the _id of
the record.
str
The _id of the record with the given name.
"""
records = client.retrieve_docdb_records(
filter_query={"name": name}, projection={"_id": 1}, limit=0
filter_query={"name": name}, projection={"_id": 1}
)

if len(records) > 1:
logging.warning(
"Multiple records share the name {name}, ",
f"Multiple records share the name {name}, "
"only the first record will be returned.",
)
elif len(records) == 0:
raise ValueError(f"No record found with name {name}")
return records[0]["_id"]

if len(records) > 0:
return records[0]["_id"]
else:
return None

def get_name_from_id(
client: MetadataDbClient,
_id: str,
) -> str:
"""
Get the name of a record in DocDb from its _id field. If no record is
found, an exception is raised.
Parameters
----------
client : MetadataDbClient
_id : str
Returns
-------
str
The name of the record with the given _id.
"""
records = client.retrieve_docdb_records(
filter_query={"_id": _id}, projection={"name": 1}, limit=1
)
if len(records) == 0:
raise ValueError(f"No record found with _id {_id}")
return records[0]["name"]
16 changes: 8 additions & 8 deletions tests/test_helpers_data_schema.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
"""Test util.data_schema module."""
"""Test helpers.data_schema module."""

from pathlib import Path
import unittest
import json
import os
import unittest
from pathlib import Path
from unittest.mock import MagicMock

from aind_data_schema.core.quality_control import QualityControl

from aind_data_access_api.helpers.data_schema import (
get_quality_control_by_id,
get_quality_control_by_name,
)
from aind_data_schema.core.quality_control import QualityControl
import os

TEST_DIR = Path(os.path.dirname(os.path.realpath(__file__)))
TEST_HELPERS_DIR = TEST_DIR / "resources" / "helpers"


class TestUtilDataSchema(unittest.TestCase):
class TestHelpersDataSchema(unittest.TestCase):
"""Test methods in data schema."""

@classmethod
Expand Down Expand Up @@ -66,7 +68,6 @@ def test_get_qc_name(self):

def test_get_qc_no_record(self):
"""Test that a value error is raised when no record exists."""
# Get json dict from test file
client = MagicMock()
client.retrieve_docdb_records.return_value = []

Expand Down Expand Up @@ -107,7 +108,6 @@ def test_get_qc_invalid_allowed(self):

def test_get_qc_no_name(self):
"""Test that a value error is raised when no record exists."""
# Get json dict from test file
client = MagicMock()
client.retrieve_docdb_records.return_value = []

Expand Down
53 changes: 49 additions & 4 deletions tests/test_helpers_docdb.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
"""Tests methods in util.docdb module"""
"""Tests methods in helpers.docdb module"""

import unittest
from unittest.mock import MagicMock
from unittest.mock import MagicMock, patch

from aind_data_access_api.helpers.docdb import (
get_record_by_id,
get_id_from_name,
get_projection_by_id,
get_field_by_id,
get_name_from_id,
)


class TestUtilDocDB(unittest.TestCase):
"""Class to test methods in util.docdb module."""
class TestHelpersDocDB(unittest.TestCase):
"""Class to test methods in helpers.docdb module."""

def test_get_id_from_name(self):
"""Tests get_id_from_name"""
Expand All @@ -22,6 +23,46 @@ def test_get_id_from_name(self):
]
self.assertEqual("abcd", get_id_from_name(client, name="123"))

@patch("logging.warning")
def test_get_id_from_name_multiple(self, mock_warning):
"""Tests get_id_from_name with multiple records"""
client = MagicMock()
client.retrieve_docdb_records.return_value = [
{"_id": "abcd"},
{"_id": "efgh"},
]
result = get_id_from_name(client, name="123")
self.assertEqual("abcd", result)
mock_warning.assert_called_once_with(
"Multiple records share the name 123, "
"only the first record will be returned."
)

def test_get_id_from_name_error(self):
"""Tests get_id_from_name with no records"""
client = MagicMock()
client.retrieve_docdb_records.return_value = []
with self.assertRaises(ValueError) as e:
get_id_from_name(client, name="123")
self.assertEqual("No record found with name 123", str(e.exception))

def test_get_name_from_id(self):
"""Tests get_name_from_id"""
client = MagicMock()
client.retrieve_docdb_records.return_value = [
{"_id": "abcd", "name": "123"}
]
result = get_name_from_id(client, _id="abcd")
self.assertEqual("123", result)

def test_get_name_from_id_error(self):
"""Tests get_name_from_id with no records"""
client = MagicMock()
client.retrieve_docdb_records.return_value = []
with self.assertRaises(ValueError) as e:
get_name_from_id(client, _id="abcd")
self.assertEqual("No record found with _id abcd", str(e.exception))

def test_get_record_from_docdb(self):
"""Tests get_record_from_docdb"""
client = MagicMock()
Expand Down Expand Up @@ -53,3 +94,7 @@ def test_get_field_from_docdb(self):
]
field = get_field_by_id(client, _id="abcd", field="quality_control")
self.assertEqual({"quality_control": {"a": 1}}, field)


if __name__ == "__main__":
unittest.main()

0 comments on commit 5d42bdf

Please sign in to comment.