Skip to content

Commit ca17791

Browse files
committed
fix: change to get request, add missing acquisition_start_time, fix modalities
1 parent b440139 commit ca17791

File tree

4 files changed

+84
-40
lines changed

4 files changed

+84
-40
lines changed

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,30 @@ else:
6565

6666
Example usage: `requests.post("https://metadata-portal.allenneuraldynamics-test.org/validate/subject", json=subject_data)`
6767

68+
### Gather endpoint
69+
70+
Get fresh metadata from the metadata service:
71+
72+
```python
73+
import requests
74+
75+
response = requests.get(
76+
"https://metadata-portal.allenneuraldynamics-test.org/gather",
77+
params={
78+
"subject_id": "804670",
79+
"project_name": "Learning mFISH-V1omFISH",
80+
"modalities": "ecephys", # comma-separated abbreviations
81+
"acquisition_start_time": "2025-09-17T10:26:00Z"
82+
}
83+
)
84+
85+
if response.status_code == 200:
86+
metadata = response.json()
87+
print(f"✅ Retrieved {list(metadata.keys())}")
88+
else:
89+
print(f"❌ Failed: {response.json()}")
90+
```
91+
6892
## Usage
6993

7094
Clone the repository and `cd` into the folder

scripts/test_gather_integration.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,33 @@ def main():
4747
print(f"📋 Subject ID: {subject_id}")
4848
print(f"📋 Project Name: {project_name}")
4949

50+
# Extract acquisition start time from existing metadata if available
51+
acquisition_start_time = None
52+
if 'acquisition' in existing_metadata and 'acquisition_start_time' in existing_metadata['acquisition']:
53+
acquisition_start_time = existing_metadata['acquisition']['acquisition_start_time']
54+
print(f"📅 Using acquisition start time: {acquisition_start_time}")
55+
5056
# Prepare gather request with some optional parameters
51-
gather_request = {
57+
gather_params = {
5258
"subject_id": subject_id,
5359
"project_name": project_name,
54-
"modalities": ["MULTIPLANE_OPHYS"], # Based on the data
55-
"tags": ["integration_test"],
60+
"modalities": "pophys", # Use abbreviation string
61+
"tags": "integration_test",
5662
"data_summary": "Integration test of gather endpoint with real metadata service"
5763
}
64+
65+
# Add acquisition_start_time if available
66+
if acquisition_start_time:
67+
gather_params["acquisition_start_time"] = acquisition_start_time
5868

5969
print("\n🚀 Calling /gather endpoint...")
60-
print(f"Request: {json.dumps(gather_request, indent=2)}")
70+
print(f"Parameters: {json.dumps(gather_params, indent=2)}")
6171

6272
# Call the gather endpoint
6373
try:
64-
response = requests.post(
74+
response = requests.get(
6575
f"{base_url}/gather",
66-
json=gather_request,
76+
params=gather_params,
6777
timeout=30
6878
)
6979

src/aind_metadata_viz/validation.py

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,14 @@
3232

3333

3434
class GatherHandler(RequestHandler):
35-
36-
def post(self):
35+
36+
def get(self):
3737
"""Gather metadata from metadata service like GatherMetadataJob"""
3838
self.set_header("Content-Type", "application/json")
39-
40-
try:
41-
data = json.loads(self.request.body)
42-
except json.JSONDecodeError:
43-
self.set_status(400)
44-
self.write({"error": "Invalid JSON format."})
45-
return
46-
47-
# Required parameters
48-
subject_id = data.get("subject_id")
49-
project_name = data.get("project_name")
39+
40+
# Required parameters from query string
41+
subject_id = self.get_argument('subject_id', None)
42+
project_name = self.get_argument('project_name', None)
5043

5144
if not subject_id:
5245
self.set_status(400)
@@ -59,14 +52,17 @@ def post(self):
5952
return
6053

6154
# Optional parameters with defaults
62-
metadata_service_url = data.get(
55+
metadata_service_url = self.get_argument(
6356
"metadata_service_url", "http://aind-metadata-service"
6457
)
65-
modalities = data.get("modalities", [])
66-
tags = data.get("tags")
67-
group = data.get("group")
68-
restrictions = data.get("restrictions")
69-
data_summary = data.get("data_summary")
58+
modalities_str = self.get_argument("modalities", "")
59+
modalities = modalities_str.split(",") if modalities_str else []
60+
tags_str = self.get_argument("tags", "")
61+
tags = tags_str.split(",") if tags_str else None
62+
group = self.get_argument("group", None)
63+
restrictions = self.get_argument("restrictions", None)
64+
data_summary = self.get_argument("data_summary", None)
65+
acquisition_start_time = self.get_argument("acquisition_start_time", None)
7066

7167
try:
7268
# Gather metadata from service
@@ -79,6 +75,7 @@ def post(self):
7975
group=group,
8076
restrictions=restrictions,
8177
data_summary=data_summary,
78+
acquisition_start_time=acquisition_start_time,
8279
)
8380

8481
self.write(result)
@@ -99,6 +96,7 @@ def _gather_metadata(
9996
group: Optional[str],
10097
restrictions: Optional[str],
10198
data_summary: Optional[str],
99+
acquisition_start_time: Optional[str],
102100
) -> dict:
103101
"""Gather and validate metadata from service"""
104102

@@ -144,6 +142,7 @@ def _gather_metadata(
144142
group=group,
145143
restrictions=restrictions,
146144
data_summary=data_summary,
145+
acquisition_start_time=acquisition_start_time,
147146
)
148147

149148
# Validate data description
@@ -255,34 +254,37 @@ def _build_data_description(
255254
group: Optional[str],
256255
restrictions: Optional[str],
257256
data_summary: Optional[str],
257+
acquisition_start_time: Optional[str],
258258
) -> dict:
259259
"""Build data description metadata with optional settings"""
260260

261-
creation_time = datetime.now(tz=timezone.utc)
261+
# Use acquisition_start_time if provided, otherwise use current time
262+
if acquisition_start_time:
263+
try:
264+
# Parse the acquisition start time (handle Z suffix)
265+
iso_time_str = acquisition_start_time.replace("Z", "+00:00")
266+
creation_time = datetime.fromisoformat(iso_time_str)
267+
except (ValueError, AttributeError):
268+
# If parsing fails, fall back to current time
269+
creation_time = datetime.now(tz=timezone.utc)
270+
else:
271+
creation_time = datetime.now(tz=timezone.utc)
262272

263273
# Get funding information
264274
funding_source, investigators = self._get_funding(
265275
project_name, metadata_service_url
266276
)
267277

268-
# Convert modalities to proper enum values if needed
278+
# Convert modalities from abbreviation strings to modality objects
269279
parsed_modalities = []
270280
for modality in modalities:
271281
if isinstance(modality, str):
272-
# Try to get modality by abbreviation first
273282
try:
274-
found_modality = Modality.from_abbreviation(
275-
modality.lower()
276-
)
283+
found_modality = Modality.from_abbreviation(modality.lower())
277284
parsed_modalities.append(found_modality)
278285
except (AttributeError, ValueError):
279-
# Try by direct attribute access
280-
try:
281-
found_modality = getattr(Modality, modality.upper())
282-
parsed_modalities.append(found_modality)
283-
except AttributeError:
284-
# Keep as string and let validation handle it
285-
parsed_modalities.append(modality)
286+
# Keep as string and let validation handle the error
287+
parsed_modalities.append(modality)
286288
else:
287289
parsed_modalities.append(modality)
288290

tests/test_validation.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
"""Test validation handlers including the GatherHandler."""
22

33
import json
4-
import unittest
5-
from unittest.mock import Mock, patch
4+
import unitte # Convert test data to query parameters
5+
query_params = []
6+
for key, value in test_data.items():
7+
if isinstance(value, list):
8+
query_params.append(f"{key}={','.join(map(str, value))}")
9+
else:
10+
query_params.append(f"{key}={value}")
11+
query_string = "&".join(query_params)
12+
13+
response = self.fetch(f'/gather?{query_string}')m unittest.mock import Mock, patch
614
import os
715
from tornado.testing import AsyncHTTPTestCase
816
from tornado.web import Application

0 commit comments

Comments
 (0)