Skip to content

Commit 85ddaae

Browse files
author
alex-omophub
committed
Implement FHIR-to-OMOP concept resolution in v1.6.0, adding methods for single and batch resolution of FHIR codings, and CodeableConcept handling. Refactor shared response parsing in API requests to improve maintainability. Update README with usage examples and correct Python version requirement in CONTRIBUTING.md.
1 parent 8091a91 commit 85ddaae

2 files changed

Lines changed: 65 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@ 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.6.0] - 2026-04-10
9+
10+
### Added
11+
12+
- **FHIR-to-OMOP Concept Resolver** (`client.fhir`): Translate FHIR coded values into OMOP standard concepts, CDM target tables, and optional Phoebe recommendations in a single API call.
13+
- `resolve()`: Resolve a single FHIR `Coding` (system URI + code) or text-only input via semantic search fallback. Returns the standard concept, target CDM table, domain alignment check, and optional mapping quality signal.
14+
- `resolve_batch()`: Batch-resolve up to 100 FHIR codings per request with inline per-item error reporting. Failed items do not fail the batch.
15+
- `resolve_codeable_concept()`: Resolve a FHIR `CodeableConcept` with multiple codings. Automatically picks the best match per OHDSI vocabulary preference (SNOMED > RxNorm > LOINC > CVX > ICD-10). Falls back to the `text` field via semantic search when no coding resolves.
16+
- New TypedDict types for FHIR resolver: `FhirResolveResult`, `FhirResolution`, `FhirBatchResult`, `FhirBatchSummary`, `FhirCodeableConceptResult`, `ResolvedConcept`, `RecommendedConceptOutput`.
17+
- Both sync (`OMOPHub`) and async (`AsyncOMOPHub`) clients support FHIR resolver methods via `client.fhir.*`.
18+
19+
### Changed
20+
21+
- **Extracted shared response parsing** (`_request.py`): The duplicated JSON decode / error-handling / rate-limit-retry logic across `Request._parse_response`, `Request._parse_response_raw`, `AsyncRequest._parse_response`, and `AsyncRequest._parse_response_raw` (4 copies of ~50 lines each) is now a single `_parse_and_raise()` module-level function. All four methods delegate to it, eliminating the risk of divergence bugs.
22+
- **Fixed `paginate_async` signature** (`_pagination.py`): The type hint now correctly declares `Callable[[int, int], Awaitable[tuple[...]]]` instead of `Callable[[int, int], tuple[...]]`, and the runtime `hasattr(__await__)` duck-typing hack has been replaced with a clean `await`.
23+
- **`AsyncSearch.semantic_iter`** now delegates to `paginate_async` instead of manually reimplementing the pagination loop, matching the sync `semantic_iter` which already uses `paginate_sync`.
24+
25+
### Fixed
26+
27+
- Python prerequisite in CONTRIBUTING.md corrected from `3.9+` to `3.10+` (matching `pyproject.toml`).
28+
- `__all__` in `types/__init__.py` sorted per RUF022.
29+
830
## [1.5.1] - 2026-04-08
931

1032
### Fixed
@@ -117,7 +139,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
117139
- Full type hints and PEP 561 compliance
118140
- HTTP/2 support via httpx
119141

120-
[Unreleased]: https://github.com/omopHub/omophub-python/compare/v1.5.1...HEAD
142+
[Unreleased]: https://github.com/omopHub/omophub-python/compare/v1.6.0...HEAD
143+
[1.6.0]: https://github.com/omopHub/omophub-python/compare/v1.5.1...v1.6.0
121144
[1.5.1]: https://github.com/omopHub/omophub-python/compare/v1.5.0...v1.5.1
122145
[1.5.0]: https://github.com/omopHub/omophub-python/compare/v1.4.1...v1.5.0
123146
[1.4.1]: https://github.com/omopHub/omophub-python/compare/v1.4.0...v1.4.1

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,46 @@ mappings = client.mappings.get_by_code("ICD10CM", "E11.9", target_vocabulary="SN
5858
ancestors = client.hierarchy.ancestors(201826, max_levels=3)
5959
```
6060

61+
## FHIR-to-OMOP Resolution
62+
63+
Resolve FHIR coded values to OMOP standard concepts in one call:
64+
65+
```python
66+
# Single FHIR Coding → OMOP concept + CDM target table
67+
result = client.fhir.resolve(
68+
system="http://snomed.info/sct",
69+
code="44054006",
70+
resource_type="Condition",
71+
)
72+
print(result["resolution"]["target_table"]) # "condition_occurrence"
73+
print(result["resolution"]["mapping_type"]) # "direct"
74+
75+
# ICD-10-CM → traverses "Maps to" automatically
76+
result = client.fhir.resolve(
77+
system="http://hl7.org/fhir/sid/icd-10-cm",
78+
code="E11.9",
79+
)
80+
print(result["resolution"]["standard_concept"]["vocabulary_id"]) # "SNOMED"
81+
82+
# Batch resolve up to 100 codings
83+
batch = client.fhir.resolve_batch([
84+
{"system": "http://snomed.info/sct", "code": "44054006"},
85+
{"system": "http://loinc.org", "code": "2339-0"},
86+
{"system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "197696"},
87+
])
88+
print(f"Resolved {batch['summary']['resolved']}/{batch['summary']['total']}")
89+
90+
# CodeableConcept with vocabulary preference (SNOMED wins over ICD-10)
91+
result = client.fhir.resolve_codeable_concept(
92+
coding=[
93+
{"system": "http://snomed.info/sct", "code": "44054006"},
94+
{"system": "http://hl7.org/fhir/sid/icd-10-cm", "code": "E11.9"},
95+
],
96+
resource_type="Condition",
97+
)
98+
print(result["best_match"]["resolution"]["source_concept"]["vocabulary_id"]) # "SNOMED"
99+
```
100+
61101
## Semantic Search
62102

63103
Use natural language queries to find concepts using neural embeddings:
@@ -200,6 +240,7 @@ suggestions = client.concepts.suggest("diab", vocabulary_ids=["SNOMED"], page_si
200240
| `mappings` | Cross-vocabulary mappings | `get()`, `map()` |
201241
| `vocabularies` | Vocabulary metadata | `list()`, `get()`, `stats()` |
202242
| `domains` | Domain information | `list()`, `get()`, `concepts()` |
243+
| `fhir` | FHIR-to-OMOP resolution | `resolve()`, `resolve_batch()`, `resolve_codeable_concept()` |
203244

204245
## Configuration
205246

0 commit comments

Comments
 (0)