Skip to content

Commit d5cb814

Browse files
author
alex-omophub
committed
Update CHANGELOG and refactor search endpoints to use new canonical path
- Updated CHANGELOG for version 1.8.1, documenting the change in API endpoint for semantic search. - Refactored `Search` and `AsyncSearch` classes to call the new canonical path `/search/semantic` instead of the deprecated `/concepts/semantic-search`. - Adjusted unit tests to reflect the updated endpoint in mock responses.
1 parent eae1f92 commit d5cb814

3 files changed

Lines changed: 27 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.8.1] - 2026-06-01
9+
10+
### Changed
11+
12+
- `Search.semantic()`, `Search.semantic_iter()`, `AsyncSearch.semantic()`, and
13+
`AsyncSearch.semantic_iter()` now call the canonical path
14+
`GET /v1/search/semantic` instead of `GET /v1/concepts/semantic-search`. The
15+
legacy path remains a permanent server-side alias (emits `Deprecation: true`
16+
+ `Link: …rel="successor-version"` headers), so older installations of this
17+
SDK continue to work - no breaking change for callers.
18+
819
## [1.8.0] - 2026-05-25
920

1021
### Added

src/omophub/resources/search.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ def semantic(
322322
if threshold is not None:
323323
params["threshold"] = threshold
324324

325-
return self._request.get("/concepts/semantic-search", params=params)
325+
return self._request.get("/search/semantic", params=params)
326326

327327
def semantic_iter(
328328
self,
@@ -369,7 +369,7 @@ def fetch_page(
369369
if threshold is not None:
370370
params["threshold"] = threshold
371371

372-
result = self._request.get_raw("/concepts/semantic-search", params=params)
372+
result = self._request.get_raw("/search/semantic", params=params)
373373

374374
data = result.get("data", [])
375375
results = data.get("results", data) if isinstance(data, dict) else data
@@ -656,7 +656,7 @@ async def semantic(
656656
if threshold is not None:
657657
params["threshold"] = threshold
658658

659-
return await self._request.get("/concepts/semantic-search", params=params)
659+
return await self._request.get("/search/semantic", params=params)
660660

661661
async def semantic_iter(
662662
self,
@@ -691,7 +691,7 @@ async def fetch_page(
691691
params["threshold"] = threshold
692692

693693
result = await self._request.get_raw(
694-
"/concepts/semantic-search", params=params
694+
"/search/semantic", params=params
695695
)
696696

697697
data = result.get("data", [])

tests/unit/resources/test_search.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ def test_semantic_search(self, sync_client: OMOPHub, base_url: str) -> None:
299299
},
300300
"meta": {"pagination": {"page": 1, "has_next": False, "total_items": 1}},
301301
}
302-
route = respx.get(f"{base_url}/concepts/semantic-search").mock(
302+
route = respx.get(f"{base_url}/search/semantic").mock(
303303
return_value=Response(200, json=semantic_response)
304304
)
305305

@@ -316,7 +316,7 @@ def test_semantic_search_with_filters(
316316
self, sync_client: OMOPHub, base_url: str
317317
) -> None:
318318
"""Test semantic search with all filters."""
319-
route = respx.get(f"{base_url}/concepts/semantic-search").mock(
319+
route = respx.get(f"{base_url}/search/semantic").mock(
320320
return_value=Response(200, json={"success": True, "data": {"results": []}})
321321
)
322322

@@ -353,7 +353,7 @@ def test_semantic_iter_single_page(
353353
],
354354
"meta": {"pagination": {"page": 1, "has_next": False}},
355355
}
356-
respx.get(f"{base_url}/concepts/semantic-search").mock(
356+
respx.get(f"{base_url}/search/semantic").mock(
357357
return_value=Response(200, json=semantic_response)
358358
)
359359

@@ -385,7 +385,7 @@ def mock_response(request):
385385
return Response(200, json=page1_response)
386386
return Response(200, json=page2_response)
387387

388-
respx.get(f"{base_url}/concepts/semantic-search").mock(side_effect=mock_response)
388+
respx.get(f"{base_url}/search/semantic").mock(side_effect=mock_response)
389389

390390
results = list(sync_client.search.semantic_iter("diabetes", page_size=1))
391391
assert len(results) == 2
@@ -402,7 +402,7 @@ def test_semantic_iter_empty_response(
402402
"data": [],
403403
"meta": {"pagination": {"page": 1, "has_next": False}},
404404
}
405-
respx.get(f"{base_url}/concepts/semantic-search").mock(
405+
respx.get(f"{base_url}/search/semantic").mock(
406406
return_value=Response(200, json=semantic_response)
407407
)
408408

@@ -555,7 +555,7 @@ async def test_async_semantic_search(
555555
"results": [{"concept_id": 4329847, "similarity_score": 0.95}],
556556
},
557557
}
558-
respx.get(f"{base_url}/concepts/semantic-search").mock(
558+
respx.get(f"{base_url}/search/semantic").mock(
559559
return_value=Response(200, json=semantic_response)
560560
)
561561

@@ -568,7 +568,7 @@ async def test_async_semantic_with_filters(
568568
self, async_client: omophub.AsyncOMOPHub, base_url: str
569569
) -> None:
570570
"""Test async semantic search with filters."""
571-
route = respx.get(f"{base_url}/concepts/semantic-search").mock(
571+
route = respx.get(f"{base_url}/search/semantic").mock(
572572
return_value=Response(200, json={"success": True, "data": {"results": []}})
573573
)
574574

@@ -591,7 +591,7 @@ async def test_async_semantic_with_all_filters(
591591
self, async_client: omophub.AsyncOMOPHub, base_url: str
592592
) -> None:
593593
"""Test async semantic search with all available filters."""
594-
route = respx.get(f"{base_url}/concepts/semantic-search").mock(
594+
route = respx.get(f"{base_url}/search/semantic").mock(
595595
return_value=Response(200, json={"success": True, "data": {"results": []}})
596596
)
597597

@@ -629,7 +629,7 @@ async def test_async_semantic_iter_single_page(
629629
],
630630
"meta": {"pagination": {"page": 1, "has_next": False}},
631631
}
632-
respx.get(f"{base_url}/concepts/semantic-search").mock(
632+
respx.get(f"{base_url}/search/semantic").mock(
633633
return_value=Response(200, json=semantic_response)
634634
)
635635

@@ -674,7 +674,7 @@ def mock_response(request):
674674
return Response(200, json=page2_response)
675675
return Response(200, json=page3_response)
676676

677-
respx.get(f"{base_url}/concepts/semantic-search").mock(side_effect=mock_response)
677+
respx.get(f"{base_url}/search/semantic").mock(side_effect=mock_response)
678678

679679
results = []
680680
async for item in async_client.search.semantic_iter("diabetes", page_size=1):
@@ -696,7 +696,7 @@ async def test_async_semantic_iter_with_filters(
696696
"data": [{"concept_id": 1, "similarity_score": 0.9}],
697697
"meta": {"pagination": {"page": 1, "has_next": False}},
698698
}
699-
route = respx.get(f"{base_url}/concepts/semantic-search").mock(
699+
route = respx.get(f"{base_url}/search/semantic").mock(
700700
return_value=Response(200, json=semantic_response)
701701
)
702702

@@ -732,7 +732,7 @@ async def test_async_semantic_iter_empty_response(
732732
"data": [],
733733
"meta": {"pagination": {"page": 1, "has_next": False}},
734734
}
735-
respx.get(f"{base_url}/concepts/semantic-search").mock(
735+
respx.get(f"{base_url}/search/semantic").mock(
736736
return_value=Response(200, json=semantic_response)
737737
)
738738

0 commit comments

Comments
 (0)