Skip to content

Commit 417268d

Browse files
authored
Merge pull request #33 from AllenNeuralDynamics/dep-update-aind-behavior-services
Update aind-behavior-services to 0.9
2 parents 974f29f + 1de040e commit 417268d

File tree

6 files changed

+391
-520
lines changed

6 files changed

+391
-520
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ dependencies = [
2222
"pydantic>=2.7, <3.0",
2323
"gitpython",
2424
"semver",
25-
"aind_behavior_services>=0.8.0, <0.9.0",
25+
"aind_behavior_services<=0.9",
2626
"aind-slims-api<0.2"
2727
]
2828

src/aind_behavior_experiment_launcher/data_mapper/helpers.py

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
import xml.etree.ElementTree as ET
77
from importlib import metadata
88
from pathlib import Path
9-
from typing import Dict, Iterable, List, Optional, Tuple, Type, TypeVar, Union, get_args
9+
from typing import Dict, List, TypeVar, Union
1010

1111
import pydantic
1212
from aind_behavior_services import (
1313
AindBehaviorRigModel,
1414
)
1515
from aind_behavior_services.rig import CameraController, CameraTypes
16+
from aind_behavior_services.utils import get_fields_of_type
1617

1718
logger = logging.getLogger(__name__)
1819

@@ -36,45 +37,6 @@ def get_cameras(
3637

3738

3839
ISearchable = Union[pydantic.BaseModel, Dict, List]
39-
_ISearchableTypeChecker = tuple(get_args(ISearchable)) # pre-compute for performance
40-
41-
42-
def get_fields_of_type(
43-
searchable: ISearchable,
44-
target_type: Type[T],
45-
*args,
46-
recursive: bool = True,
47-
stop_recursion_on_type: bool = True,
48-
**kwargs,
49-
) -> List[Tuple[Optional[str], T]]:
50-
_iterable: Iterable
51-
_is_type: bool
52-
result: List[Tuple[Optional[str], T]] = []
53-
54-
if isinstance(searchable, dict):
55-
_iterable = searchable.items()
56-
elif isinstance(searchable, list):
57-
_iterable = list(zip([None for _ in range(len(searchable))], searchable))
58-
elif isinstance(searchable, pydantic.BaseModel):
59-
_iterable = {k: getattr(searchable, k) for k in searchable.model_fields.keys()}.items()
60-
else:
61-
raise ValueError(f"Unsupported model type: {type(searchable)}")
62-
63-
for name, field in _iterable:
64-
_is_type = False
65-
if isinstance(field, target_type):
66-
result.append((name, field))
67-
_is_type = True
68-
if recursive and isinstance(field, _ISearchableTypeChecker) and not (stop_recursion_on_type and _is_type):
69-
result.extend(
70-
get_fields_of_type(
71-
field,
72-
target_type,
73-
recursive=recursive,
74-
stop_recursion_on_type=stop_recursion_on_type,
75-
)
76-
)
77-
return result
7840

7941

8042
def _sanity_snapshot_keys(snapshot: Dict[str, str]) -> Dict[str, str]:

src/aind_behavior_experiment_launcher/data_transfer/aind_watchdog.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def transfer(self) -> None:
100100
self.force_restart(kill_if_running=False)
101101
except subprocess.CalledProcessError as e:
102102
logger.error("Failed to start watchdog service. %s", e)
103-
raise RuntimeError("Failed to start watchdog service.")
103+
raise RuntimeError("Failed to start watchdog service.") from e
104104
else:
105105
if not self.is_running():
106106
logger.error("Failed to start watchdog service.")
@@ -260,10 +260,10 @@ def _get_project_names(
260260
) -> list[str]:
261261
response = requests.get(end_point, timeout=timeout)
262262
if response.ok:
263-
content = json.loads(response.content)
263+
return json.loads(response.content)["data"]
264264
else:
265265
response.raise_for_status()
266-
return content["data"]
266+
raise HTTPError(f"Failed to fetch project names from endpoint. {response.content}")
267267

268268
def is_running(self) -> bool:
269269
output = subprocess.check_output(
@@ -290,7 +290,7 @@ def dump_manifest_config(self, path: Optional[os.PathLike] = None, make_dir: boo
290290

291291
path = (Path(path) if path else Path(watch_config.flag_dir) / f"manifest_{manifest_config.name}.yaml").resolve()
292292
if "manifest" not in path.name:
293-
logger.warning("Prefix " "manifest_" " not found in file name. Appending it.")
293+
logger.warning("Prefix manifest_ not found in file name. Appending it.")
294294
path = path.with_name(f"manifest_{path.name}.yaml")
295295

296296
if make_dir and not path.parent.exists():

src/aind_behavior_experiment_launcher/ui_helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def prompt_pick_file_from_list(
3232
if zero_label is not None:
3333
self._print(f"0: {zero_label}")
3434
for i, file in enumerate(available_files):
35-
self._print(f"{i+1}: {os.path.split(file)[1]}")
35+
self._print(f"{i + 1}: {os.path.split(file)[1]}")
3636
choice = int(input("Choice: "))
3737
if choice < 0 or choice >= len(available_files) + 1:
3838
raise ValueError

tests/test_data_mapper.py

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import unittest
2-
3-
# from . import TESTS_ASSETS, REPO_ROOT
42
from pathlib import Path
53
from typing import Dict, List, Optional
64
from unittest.mock import patch
@@ -9,12 +7,10 @@
97

108
from aind_behavior_experiment_launcher.data_mapper.helpers import (
119
_sanity_snapshot_keys,
12-
get_fields_of_type,
1310
snapshot_bonsai_environment,
1411
snapshot_python_environment,
1512
)
16-
17-
from . import TESTS_ASSETS
13+
from tests import TESTS_ASSETS
1814

1915

2016
class MockModel(BaseModel):
@@ -26,57 +22,6 @@ class MockModel(BaseModel):
2622
sub_model: Optional["MockModel"] = None
2723

2824

29-
class TestGetFieldsOfType(unittest.TestCase):
30-
def test_get_fields_of_type_dict(self):
31-
data = {"field1": 1, "field2": "test", "field3": [1, 2, 3], "field4": {"key1": 1, "key2": 2}, "field5": None}
32-
result = get_fields_of_type(data, int, recursive=False)
33-
expected = [("field1", 1)]
34-
self.assertEqual(result, expected)
35-
36-
result = get_fields_of_type(data, int, recursive=True)
37-
expected = [("field1", 1), (None, 1), (None, 2), (None, 3), ("key1", 1), ("key2", 2)]
38-
self.assertEqual(result, expected)
39-
40-
def test_get_fields_of_type_list(self):
41-
data = [1, "test", [1, 2, 3], {"key1": 1, "key2": 2}, None]
42-
result = get_fields_of_type(data, int, recursive=False)
43-
expected = [(None, 1)]
44-
self.assertEqual(result, expected)
45-
46-
result = get_fields_of_type(data, int, recursive=True)
47-
expected = [(None, 1), (None, 1), (None, 2), (None, 3), ("key1", 1), ("key2", 2)]
48-
self.assertEqual(result, expected)
49-
50-
def test_get_fields_of_type_pydantic_model(self):
51-
model = MockModel(field1=1, field2="test", field3=[1, 2, 3], field4={"key1": 1, "key2": 2})
52-
result = get_fields_of_type(model, int, recursive=False)
53-
expected = [("field1", 1)]
54-
self.assertEqual(result, expected)
55-
56-
result = get_fields_of_type(model, int, recursive=True)
57-
expected = [("field1", 1), (None, 1), (None, 2), (None, 3), ("key1", 1), ("key2", 2)]
58-
self.assertEqual(result, expected)
59-
60-
def test_get_fields_of_type_stop_recursion(self):
61-
sub_model = MockModel(field1=1, field2="test", field3=[1, 3, 36], field4={"key1": 2, "key2": 3})
62-
model = MockModel(field1=1, field2="test", field3=[1, 2, 3], field4={"key1": 1, "key2": 2}, sub_model=sub_model)
63-
data = {
64-
"field1": 1,
65-
"field2": "test",
66-
"field3": [1, 2, {"nested_field": 3}],
67-
"field4": {"key1": 1, "key2": 2},
68-
"field5": None,
69-
"field6": model,
70-
}
71-
result = get_fields_of_type(data, MockModel, recursive=True, stop_recursion_on_type=True)
72-
expected = [("field6", model)]
73-
self.assertEqual(result, expected)
74-
75-
result = get_fields_of_type(data, MockModel, recursive=True, stop_recursion_on_type=False)
76-
expected = [("field6", model), ("sub_model", sub_model)]
77-
self.assertEqual(result, expected)
78-
79-
8025
class TestHelpers(unittest.TestCase):
8126
@patch("importlib.metadata.distributions")
8227
def test_snapshot_python_environment(self, mock_distributions):

0 commit comments

Comments
 (0)