brightohir 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- brightohir-1.0.0/LICENSE +24 -0
- brightohir-1.0.0/MANIFEST.in +4 -0
- brightohir-1.0.0/PKG-INFO +234 -0
- brightohir-1.0.0/README.md +189 -0
- brightohir-1.0.0/pyproject.toml +64 -0
- brightohir-1.0.0/setup.cfg +4 -0
- brightohir-1.0.0/src/brightohir/__init__.py +66 -0
- brightohir-1.0.0/src/brightohir/convert_r4r5.py +407 -0
- brightohir-1.0.0/src/brightohir/convert_v2.py +1113 -0
- brightohir-1.0.0/src/brightohir/mappings/__init__.py +1 -0
- brightohir-1.0.0/src/brightohir/py.typed +0 -0
- brightohir-1.0.0/src/brightohir/r5.py +149 -0
- brightohir-1.0.0/src/brightohir/registry.py +552 -0
- brightohir-1.0.0/src/brightohir.egg-info/PKG-INFO +234 -0
- brightohir-1.0.0/src/brightohir.egg-info/SOURCES.txt +17 -0
- brightohir-1.0.0/src/brightohir.egg-info/dependency_links.txt +1 -0
- brightohir-1.0.0/src/brightohir.egg-info/requires.txt +21 -0
- brightohir-1.0.0/src/brightohir.egg-info/top_level.txt +1 -0
- brightohir-1.0.0/tests/test_sdk.py +422 -0
brightohir-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BrighTO Technology / Hatto AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
FHIR® is the registered trademark of HL7 and is used with the permission of HL7.
|
|
24
|
+
HL7® is a registered trademark of Health Level Seven International.
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: brightohir
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: BrighTO HL7 Interoperability Runtime — FHIR R5, R4↔R5, V2.x↔R5 Python SDK
|
|
5
|
+
Author: BrighTO Technology / Hatto AI
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/BrighTOTechnology/brightohir
|
|
8
|
+
Project-URL: Documentation, https://github.com/BrighTOTechnology/brightohir#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/BrighTOTechnology/brightohir
|
|
10
|
+
Project-URL: Issues, https://github.com/BrighTOTechnology/brightohir/issues
|
|
11
|
+
Keywords: hl7,fhir,fhir-r5,healthcare,interoperability,hl7v2,pharmacy,ehr,clinical,medical
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Healthcare Industry
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: fhir.resources>=8.0.0
|
|
28
|
+
Requires-Dist: fhir-core>=1.1.0
|
|
29
|
+
Requires-Dist: hl7apy>=1.3.5
|
|
30
|
+
Requires-Dist: pyyaml>=6.0
|
|
31
|
+
Provides-Extra: client
|
|
32
|
+
Requires-Dist: fhirpy>=2.2.0; extra == "client"
|
|
33
|
+
Provides-Extra: fhirpath
|
|
34
|
+
Requires-Dist: fhirpathpy>=0.2.0; extra == "fhirpath"
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
38
|
+
Requires-Dist: ruff; extra == "dev"
|
|
39
|
+
Requires-Dist: build; extra == "dev"
|
|
40
|
+
Requires-Dist: twine; extra == "dev"
|
|
41
|
+
Provides-Extra: all
|
|
42
|
+
Requires-Dist: fhirpy>=2.2.0; extra == "all"
|
|
43
|
+
Requires-Dist: fhirpathpy>=0.2.0; extra == "all"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
# brightohir — BrighTO HL7 Interoperability Runtime
|
|
47
|
+
|
|
48
|
+
Production-grade Python SDK for **FHIR R5**, **R4↔R5 conversion**, and **HL7 V2.x↔R5 bidirectional conversion**.
|
|
49
|
+
|
|
50
|
+
## Standards Compliance
|
|
51
|
+
|
|
52
|
+
| Standard | Version | Coverage |
|
|
53
|
+
|----------|---------|----------|
|
|
54
|
+
| FHIR R5 | v5.0.0 | All 157 resources |
|
|
55
|
+
| HL7 V2-to-FHIR IG | v1.0.0 STU (Oct 2025) | 50+ segment maps, 25+ message structures, 30+ datatype maps, 40+ vocabulary maps |
|
|
56
|
+
| FHIR R4↔R5 | Official StructureMaps | 50+ resource transforms with field-level diffs |
|
|
57
|
+
| HL7 V2.x | 2.1–2.8.2 (via hl7apy) | Full parse/create/validate |
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install fhir.resources hl7apy pyyaml # core deps
|
|
63
|
+
pip install fhirpy # optional: FHIR server client
|
|
64
|
+
pip install fhirpathpy # optional: FHIRPath expressions
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Quick Start
|
|
68
|
+
|
|
69
|
+
### 1. Create FHIR R5 Resources
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from brightohir import R5
|
|
73
|
+
|
|
74
|
+
# Create a Patient
|
|
75
|
+
patient = R5.create("Patient",
|
|
76
|
+
id="p001", active=True,
|
|
77
|
+
name=[{"family": "Nguyen", "given": ["Van A"]}],
|
|
78
|
+
gender="male", birthDate="1990-01-15")
|
|
79
|
+
|
|
80
|
+
# Create an Observation
|
|
81
|
+
obs = R5.create("Observation",
|
|
82
|
+
id="obs001", status="final",
|
|
83
|
+
code={"coding": [{"system": "http://loinc.org", "code": "29463-7", "display": "Body Weight"}]},
|
|
84
|
+
valueQuantity={"value": 72, "unit": "kg"})
|
|
85
|
+
|
|
86
|
+
# Build a Bundle
|
|
87
|
+
bundle = R5.bundle("transaction", [patient, obs])
|
|
88
|
+
|
|
89
|
+
# Serialize
|
|
90
|
+
json_str = R5.to_json(patient)
|
|
91
|
+
patient_dict = R5.to_dict(patient)
|
|
92
|
+
|
|
93
|
+
# Validate
|
|
94
|
+
errors = R5.validate("Patient", {"active": "INVALID"})
|
|
95
|
+
# Returns list of error strings (empty = valid)
|
|
96
|
+
|
|
97
|
+
# List all 157 R5 resources
|
|
98
|
+
all_types = R5.list_resources()
|
|
99
|
+
meds = R5.list_resources("medications") # Category filter
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 2. R4 ↔ R5 Conversion
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from brightohir import r4_to_r5, r5_to_r4, conversion_status
|
|
106
|
+
|
|
107
|
+
# R4 → R5 (handles breaking changes automatically)
|
|
108
|
+
r4_encounter = {
|
|
109
|
+
"resourceType": "Encounter", "id": "enc-001", "status": "in-progress",
|
|
110
|
+
"class": {"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "AMB"},
|
|
111
|
+
"hospitalization": {"dischargeDisposition": {"text": "home"}},
|
|
112
|
+
}
|
|
113
|
+
r5_encounter = r4_to_r5(r4_encounter)
|
|
114
|
+
# class: Coding → CodeableConcept[]
|
|
115
|
+
# hospitalization → admission
|
|
116
|
+
# classHistory/statusHistory removed
|
|
117
|
+
|
|
118
|
+
# R5 → R4 (downgrades gracefully)
|
|
119
|
+
r4_back = r5_to_r4(r5_encounter)
|
|
120
|
+
|
|
121
|
+
# MedicationRequest: medication[x] → CodeableReference
|
|
122
|
+
r4_med = {
|
|
123
|
+
"resourceType": "MedicationRequest", "status": "active", "intent": "order",
|
|
124
|
+
"medicationCodeableConcept": {"coding": [{"code": "12345"}]},
|
|
125
|
+
}
|
|
126
|
+
r5_med = r4_to_r5(r4_med)
|
|
127
|
+
# r5_med["medication"]["concept"]["coding"][0]["code"] == "12345"
|
|
128
|
+
|
|
129
|
+
# Check conversion status for any resource
|
|
130
|
+
info = conversion_status("Encounter")
|
|
131
|
+
# {"r5": "Encounter", "r4": "Encounter", "status": "restructured", "changes": [...]}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 3. V2.x → FHIR R5
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from brightohir import v2_to_r5, V2Converter
|
|
138
|
+
|
|
139
|
+
# Quick convert
|
|
140
|
+
adt_a01 = """MSH|^~\\&|HATTO|LC_PHARMACY|EHR|HOSPITAL|20260322090000||ADT^A01^ADT_A01|MSG001|P|2.5.1
|
|
141
|
+
PID|1||12345^^^LC^MR||NGUYEN^VAN A||19900115|M|||123 NGUYEN HUE^^HCM^VN^70000
|
|
142
|
+
PV1|1|I|W^101^1|||12345^TRAN^BAC SI|||MED
|
|
143
|
+
AL1|1|DA|ASPIRIN|SV|Rash
|
|
144
|
+
DG1|1||J06.9^URTI^ICD10|||A
|
|
145
|
+
OBX|1|NM|29463-7^Body Weight^LN||72|kg|||||F"""
|
|
146
|
+
|
|
147
|
+
bundle = v2_to_r5(adt_a01)
|
|
148
|
+
# Returns FHIR R5 Bundle with: MessageHeader, Patient, Encounter,
|
|
149
|
+
# AllergyIntolerance, Condition, Observation — all cross-referenced
|
|
150
|
+
|
|
151
|
+
# Full control with V2Converter
|
|
152
|
+
conv = V2Converter()
|
|
153
|
+
bundle = conv.convert(adt_a01)
|
|
154
|
+
patient = conv.extract_resource("Patient") # First Patient
|
|
155
|
+
obs_list = conv.extract_all("Observation") # All Observations
|
|
156
|
+
encounter = conv.extract_resource("Encounter") # First Encounter
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 4. FHIR R5 → V2.x
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from brightohir import r5_to_v2
|
|
163
|
+
|
|
164
|
+
# Single resource
|
|
165
|
+
patient_dict = {
|
|
166
|
+
"resourceType": "Patient", "id": "p001",
|
|
167
|
+
"name": [{"family": "Nguyen", "given": ["Van A"]}],
|
|
168
|
+
"gender": "male", "birthDate": "1990-01-15",
|
|
169
|
+
}
|
|
170
|
+
v2_msg = r5_to_v2(patient_dict, message_type="ADT_A01")
|
|
171
|
+
# MSH|^~\&|BRIGHTOHIR||EXTERNAL||20260322...|ADT^A01^ADT_A01|...
|
|
172
|
+
# EVN|A01|...
|
|
173
|
+
# PID|...|Nguyen^Van A||19900115|M
|
|
174
|
+
|
|
175
|
+
# From a Bundle
|
|
176
|
+
v2_msg = r5_to_v2(bundle_dict, message_type="ADT_A01",
|
|
177
|
+
sending_app="LC_PHARMACY", receiving_app="HIS")
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 5. Access the Registry
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from brightohir import (
|
|
184
|
+
ALL_R5_RESOURCES, # Set of all 157 R5 resource names
|
|
185
|
+
R5_RESOURCES, # Dict by category
|
|
186
|
+
V2_SEGMENT_TO_FHIR, # PID → [(Patient, ""), ...], OBX → [(Observation, ""), ...]
|
|
187
|
+
V2_MESSAGE_TO_FHIR, # ADT_A01 → {segments, fhir_resources}
|
|
188
|
+
V2_DATATYPE_TO_FHIR, # CWE → [CodeableConcept, Coding, ...], XPN → [HumanName]
|
|
189
|
+
V2_TABLE_TO_FHIR_SYSTEM, # HL70001 → admin-gender URI
|
|
190
|
+
R4_TO_R5_MAP, # Encounter → {status, changes, ...}
|
|
191
|
+
)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Architecture
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
brightohir/
|
|
198
|
+
├── __init__.py # Public API
|
|
199
|
+
├── r5.py # R5 resource factory (create/validate/serialize)
|
|
200
|
+
├── convert_r4r5.py # R4 ↔ R5 bidirectional converter
|
|
201
|
+
├── convert_v2.py # V2.x ↔ R5 bidirectional converter
|
|
202
|
+
├── registry.py # Standards registry (157 resources, mappings, diffs)
|
|
203
|
+
└── mappings/ # YAML configs (extensible)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Supported V2 Message Types
|
|
207
|
+
|
|
208
|
+
ADT: A01, A02, A03, A04, A05, A08, A28, A31, A34, A40 •
|
|
209
|
+
ORM/ORU: O01, R01 • OML: O21 • OUL: R22 •
|
|
210
|
+
Pharmacy: RDE_O11, RDS_O13, RAS_O17 •
|
|
211
|
+
Vaccination: VXU_V04 • Documents: MDM_T02 •
|
|
212
|
+
Scheduling: SIU_S12–S15 • Financial: BAR_P01, DFT_P03
|
|
213
|
+
|
|
214
|
+
## Supported V2 Segment Converters
|
|
215
|
+
|
|
216
|
+
| Segment | → FHIR R5 Resource | Fields Mapped |
|
|
217
|
+
|---------|-------|------|
|
|
218
|
+
| PID | Patient | identifier, name, birthDate, gender, address, telecom, maritalStatus, communication, deceased |
|
|
219
|
+
| PV1 | Encounter | class, actualPeriod, admission |
|
|
220
|
+
| OBX | Observation | code, value[x], units, interpretation, status, effectiveDateTime, referenceRange |
|
|
221
|
+
| AL1 | AllergyIntolerance | type, category, code, criticality, reaction, onset |
|
|
222
|
+
| DG1 | Condition | code, onset, category, clinicalStatus |
|
|
223
|
+
| RXA | Immunization | occurrenceDateTime, vaccineCode, doseQuantity, lotNumber, status |
|
|
224
|
+
| MSH | MessageHeader | eventCoding, source, destination |
|
|
225
|
+
|
|
226
|
+
## Dependencies
|
|
227
|
+
|
|
228
|
+
- `fhir.resources` ≥8.0.0 — FHIR R5 Pydantic models (production-stable, Feb 2026)
|
|
229
|
+
- `hl7apy` ≥1.3.5 — V2.x parse/create/validate (V2.1–2.8.2)
|
|
230
|
+
- `pyyaml` ≥6.0 — YAML mapping configs
|
|
231
|
+
|
|
232
|
+
## License
|
|
233
|
+
|
|
234
|
+
MIT — BrighTO Technology / Hatto AI
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# brightohir — BrighTO HL7 Interoperability Runtime
|
|
2
|
+
|
|
3
|
+
Production-grade Python SDK for **FHIR R5**, **R4↔R5 conversion**, and **HL7 V2.x↔R5 bidirectional conversion**.
|
|
4
|
+
|
|
5
|
+
## Standards Compliance
|
|
6
|
+
|
|
7
|
+
| Standard | Version | Coverage |
|
|
8
|
+
|----------|---------|----------|
|
|
9
|
+
| FHIR R5 | v5.0.0 | All 157 resources |
|
|
10
|
+
| HL7 V2-to-FHIR IG | v1.0.0 STU (Oct 2025) | 50+ segment maps, 25+ message structures, 30+ datatype maps, 40+ vocabulary maps |
|
|
11
|
+
| FHIR R4↔R5 | Official StructureMaps | 50+ resource transforms with field-level diffs |
|
|
12
|
+
| HL7 V2.x | 2.1–2.8.2 (via hl7apy) | Full parse/create/validate |
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install fhir.resources hl7apy pyyaml # core deps
|
|
18
|
+
pip install fhirpy # optional: FHIR server client
|
|
19
|
+
pip install fhirpathpy # optional: FHIRPath expressions
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### 1. Create FHIR R5 Resources
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from brightohir import R5
|
|
28
|
+
|
|
29
|
+
# Create a Patient
|
|
30
|
+
patient = R5.create("Patient",
|
|
31
|
+
id="p001", active=True,
|
|
32
|
+
name=[{"family": "Nguyen", "given": ["Van A"]}],
|
|
33
|
+
gender="male", birthDate="1990-01-15")
|
|
34
|
+
|
|
35
|
+
# Create an Observation
|
|
36
|
+
obs = R5.create("Observation",
|
|
37
|
+
id="obs001", status="final",
|
|
38
|
+
code={"coding": [{"system": "http://loinc.org", "code": "29463-7", "display": "Body Weight"}]},
|
|
39
|
+
valueQuantity={"value": 72, "unit": "kg"})
|
|
40
|
+
|
|
41
|
+
# Build a Bundle
|
|
42
|
+
bundle = R5.bundle("transaction", [patient, obs])
|
|
43
|
+
|
|
44
|
+
# Serialize
|
|
45
|
+
json_str = R5.to_json(patient)
|
|
46
|
+
patient_dict = R5.to_dict(patient)
|
|
47
|
+
|
|
48
|
+
# Validate
|
|
49
|
+
errors = R5.validate("Patient", {"active": "INVALID"})
|
|
50
|
+
# Returns list of error strings (empty = valid)
|
|
51
|
+
|
|
52
|
+
# List all 157 R5 resources
|
|
53
|
+
all_types = R5.list_resources()
|
|
54
|
+
meds = R5.list_resources("medications") # Category filter
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 2. R4 ↔ R5 Conversion
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from brightohir import r4_to_r5, r5_to_r4, conversion_status
|
|
61
|
+
|
|
62
|
+
# R4 → R5 (handles breaking changes automatically)
|
|
63
|
+
r4_encounter = {
|
|
64
|
+
"resourceType": "Encounter", "id": "enc-001", "status": "in-progress",
|
|
65
|
+
"class": {"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", "code": "AMB"},
|
|
66
|
+
"hospitalization": {"dischargeDisposition": {"text": "home"}},
|
|
67
|
+
}
|
|
68
|
+
r5_encounter = r4_to_r5(r4_encounter)
|
|
69
|
+
# class: Coding → CodeableConcept[]
|
|
70
|
+
# hospitalization → admission
|
|
71
|
+
# classHistory/statusHistory removed
|
|
72
|
+
|
|
73
|
+
# R5 → R4 (downgrades gracefully)
|
|
74
|
+
r4_back = r5_to_r4(r5_encounter)
|
|
75
|
+
|
|
76
|
+
# MedicationRequest: medication[x] → CodeableReference
|
|
77
|
+
r4_med = {
|
|
78
|
+
"resourceType": "MedicationRequest", "status": "active", "intent": "order",
|
|
79
|
+
"medicationCodeableConcept": {"coding": [{"code": "12345"}]},
|
|
80
|
+
}
|
|
81
|
+
r5_med = r4_to_r5(r4_med)
|
|
82
|
+
# r5_med["medication"]["concept"]["coding"][0]["code"] == "12345"
|
|
83
|
+
|
|
84
|
+
# Check conversion status for any resource
|
|
85
|
+
info = conversion_status("Encounter")
|
|
86
|
+
# {"r5": "Encounter", "r4": "Encounter", "status": "restructured", "changes": [...]}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 3. V2.x → FHIR R5
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from brightohir import v2_to_r5, V2Converter
|
|
93
|
+
|
|
94
|
+
# Quick convert
|
|
95
|
+
adt_a01 = """MSH|^~\\&|HATTO|LC_PHARMACY|EHR|HOSPITAL|20260322090000||ADT^A01^ADT_A01|MSG001|P|2.5.1
|
|
96
|
+
PID|1||12345^^^LC^MR||NGUYEN^VAN A||19900115|M|||123 NGUYEN HUE^^HCM^VN^70000
|
|
97
|
+
PV1|1|I|W^101^1|||12345^TRAN^BAC SI|||MED
|
|
98
|
+
AL1|1|DA|ASPIRIN|SV|Rash
|
|
99
|
+
DG1|1||J06.9^URTI^ICD10|||A
|
|
100
|
+
OBX|1|NM|29463-7^Body Weight^LN||72|kg|||||F"""
|
|
101
|
+
|
|
102
|
+
bundle = v2_to_r5(adt_a01)
|
|
103
|
+
# Returns FHIR R5 Bundle with: MessageHeader, Patient, Encounter,
|
|
104
|
+
# AllergyIntolerance, Condition, Observation — all cross-referenced
|
|
105
|
+
|
|
106
|
+
# Full control with V2Converter
|
|
107
|
+
conv = V2Converter()
|
|
108
|
+
bundle = conv.convert(adt_a01)
|
|
109
|
+
patient = conv.extract_resource("Patient") # First Patient
|
|
110
|
+
obs_list = conv.extract_all("Observation") # All Observations
|
|
111
|
+
encounter = conv.extract_resource("Encounter") # First Encounter
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 4. FHIR R5 → V2.x
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from brightohir import r5_to_v2
|
|
118
|
+
|
|
119
|
+
# Single resource
|
|
120
|
+
patient_dict = {
|
|
121
|
+
"resourceType": "Patient", "id": "p001",
|
|
122
|
+
"name": [{"family": "Nguyen", "given": ["Van A"]}],
|
|
123
|
+
"gender": "male", "birthDate": "1990-01-15",
|
|
124
|
+
}
|
|
125
|
+
v2_msg = r5_to_v2(patient_dict, message_type="ADT_A01")
|
|
126
|
+
# MSH|^~\&|BRIGHTOHIR||EXTERNAL||20260322...|ADT^A01^ADT_A01|...
|
|
127
|
+
# EVN|A01|...
|
|
128
|
+
# PID|...|Nguyen^Van A||19900115|M
|
|
129
|
+
|
|
130
|
+
# From a Bundle
|
|
131
|
+
v2_msg = r5_to_v2(bundle_dict, message_type="ADT_A01",
|
|
132
|
+
sending_app="LC_PHARMACY", receiving_app="HIS")
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 5. Access the Registry
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from brightohir import (
|
|
139
|
+
ALL_R5_RESOURCES, # Set of all 157 R5 resource names
|
|
140
|
+
R5_RESOURCES, # Dict by category
|
|
141
|
+
V2_SEGMENT_TO_FHIR, # PID → [(Patient, ""), ...], OBX → [(Observation, ""), ...]
|
|
142
|
+
V2_MESSAGE_TO_FHIR, # ADT_A01 → {segments, fhir_resources}
|
|
143
|
+
V2_DATATYPE_TO_FHIR, # CWE → [CodeableConcept, Coding, ...], XPN → [HumanName]
|
|
144
|
+
V2_TABLE_TO_FHIR_SYSTEM, # HL70001 → admin-gender URI
|
|
145
|
+
R4_TO_R5_MAP, # Encounter → {status, changes, ...}
|
|
146
|
+
)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Architecture
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
brightohir/
|
|
153
|
+
├── __init__.py # Public API
|
|
154
|
+
├── r5.py # R5 resource factory (create/validate/serialize)
|
|
155
|
+
├── convert_r4r5.py # R4 ↔ R5 bidirectional converter
|
|
156
|
+
├── convert_v2.py # V2.x ↔ R5 bidirectional converter
|
|
157
|
+
├── registry.py # Standards registry (157 resources, mappings, diffs)
|
|
158
|
+
└── mappings/ # YAML configs (extensible)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Supported V2 Message Types
|
|
162
|
+
|
|
163
|
+
ADT: A01, A02, A03, A04, A05, A08, A28, A31, A34, A40 •
|
|
164
|
+
ORM/ORU: O01, R01 • OML: O21 • OUL: R22 •
|
|
165
|
+
Pharmacy: RDE_O11, RDS_O13, RAS_O17 •
|
|
166
|
+
Vaccination: VXU_V04 • Documents: MDM_T02 •
|
|
167
|
+
Scheduling: SIU_S12–S15 • Financial: BAR_P01, DFT_P03
|
|
168
|
+
|
|
169
|
+
## Supported V2 Segment Converters
|
|
170
|
+
|
|
171
|
+
| Segment | → FHIR R5 Resource | Fields Mapped |
|
|
172
|
+
|---------|-------|------|
|
|
173
|
+
| PID | Patient | identifier, name, birthDate, gender, address, telecom, maritalStatus, communication, deceased |
|
|
174
|
+
| PV1 | Encounter | class, actualPeriod, admission |
|
|
175
|
+
| OBX | Observation | code, value[x], units, interpretation, status, effectiveDateTime, referenceRange |
|
|
176
|
+
| AL1 | AllergyIntolerance | type, category, code, criticality, reaction, onset |
|
|
177
|
+
| DG1 | Condition | code, onset, category, clinicalStatus |
|
|
178
|
+
| RXA | Immunization | occurrenceDateTime, vaccineCode, doseQuantity, lotNumber, status |
|
|
179
|
+
| MSH | MessageHeader | eventCoding, source, destination |
|
|
180
|
+
|
|
181
|
+
## Dependencies
|
|
182
|
+
|
|
183
|
+
- `fhir.resources` ≥8.0.0 — FHIR R5 Pydantic models (production-stable, Feb 2026)
|
|
184
|
+
- `hl7apy` ≥1.3.5 — V2.x parse/create/validate (V2.1–2.8.2)
|
|
185
|
+
- `pyyaml` ≥6.0 — YAML mapping configs
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT — BrighTO Technology / Hatto AI
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "brightohir"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "BrighTO HL7 Interoperability Runtime — FHIR R5, R4↔R5, V2.x↔R5 Python SDK"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "BrighTO Technology / Hatto AI"},
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"hl7", "fhir", "fhir-r5", "healthcare", "interoperability",
|
|
17
|
+
"hl7v2", "pharmacy", "ehr", "clinical", "medical",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 5 - Production/Stable",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Intended Audience :: Healthcare Industry",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Topic :: Scientific/Engineering :: Medical Science Apps.",
|
|
30
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
31
|
+
"Typing :: Typed",
|
|
32
|
+
]
|
|
33
|
+
dependencies = [
|
|
34
|
+
"fhir.resources>=8.0.0",
|
|
35
|
+
"fhir-core>=1.1.0",
|
|
36
|
+
"hl7apy>=1.3.5",
|
|
37
|
+
"pyyaml>=6.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
client = ["fhirpy>=2.2.0"]
|
|
42
|
+
fhirpath = ["fhirpathpy>=0.2.0"]
|
|
43
|
+
dev = ["pytest>=8.0", "pytest-cov", "ruff", "build", "twine"]
|
|
44
|
+
all = ["fhirpy>=2.2.0", "fhirpathpy>=0.2.0"]
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Homepage = "https://github.com/BrighTOTechnology/brightohir"
|
|
48
|
+
Documentation = "https://github.com/BrighTOTechnology/brightohir#readme"
|
|
49
|
+
Repository = "https://github.com/BrighTOTechnology/brightohir"
|
|
50
|
+
Issues = "https://github.com/BrighTOTechnology/brightohir/issues"
|
|
51
|
+
|
|
52
|
+
[tool.setuptools.packages.find]
|
|
53
|
+
where = ["src"]
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.package-data]
|
|
56
|
+
brightohir = ["py.typed", "mappings/*.yaml"]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
pythonpath = ["src"]
|
|
61
|
+
|
|
62
|
+
[tool.ruff]
|
|
63
|
+
target-version = "py310"
|
|
64
|
+
line-length = 120
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""
|
|
2
|
+
brightohir — BrighTO HL7 Interoperability Runtime
|
|
3
|
+
==================================================
|
|
4
|
+
Production-grade Python SDK for FHIR R5, R4↔R5, and V2.x↔R5 conversion.
|
|
5
|
+
|
|
6
|
+
Standards compliance:
|
|
7
|
+
- FHIR R5 v5.0.0 (157 resources)
|
|
8
|
+
- HL7 V2-to-FHIR IG v1.0.0 STU (Oct 2025)
|
|
9
|
+
- FHIR R4↔R5 official StructureMaps
|
|
10
|
+
|
|
11
|
+
Quick start:
|
|
12
|
+
from brightohir import R5, v2_to_r5, r5_to_v2, r4_to_r5, r5_to_r4
|
|
13
|
+
|
|
14
|
+
# Create R5 resource
|
|
15
|
+
patient = R5.create("Patient", id="p001", active=True,
|
|
16
|
+
name=[{"family": "Nguyen", "given": ["Van A"]}])
|
|
17
|
+
|
|
18
|
+
# V2 → R5
|
|
19
|
+
bundle = v2_to_r5(adt_a01_string)
|
|
20
|
+
|
|
21
|
+
# R5 → V2
|
|
22
|
+
v2_msg = r5_to_v2(patient_dict, message_type="ADT_A01")
|
|
23
|
+
|
|
24
|
+
# R4 ↔ R5
|
|
25
|
+
r5_data = r4_to_r5(r4_encounter_dict)
|
|
26
|
+
r4_data = r5_to_r4(r5_encounter_dict)
|
|
27
|
+
|
|
28
|
+
Install:
|
|
29
|
+
pip install fhir.resources hl7apy pyyaml
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
__version__ = "1.0.0"
|
|
33
|
+
|
|
34
|
+
from .r5 import R5
|
|
35
|
+
from .convert_r4r5 import r4_to_r5, r5_to_r4, conversion_status
|
|
36
|
+
from .convert_v2 import v2_to_r5, r5_to_v2, V2Converter
|
|
37
|
+
from .registry import (
|
|
38
|
+
ALL_R5_RESOURCES,
|
|
39
|
+
R5_RESOURCES,
|
|
40
|
+
R4_TO_R5_MAP,
|
|
41
|
+
V2_SEGMENT_TO_FHIR,
|
|
42
|
+
V2_MESSAGE_TO_FHIR,
|
|
43
|
+
V2_DATATYPE_TO_FHIR,
|
|
44
|
+
V2_TABLE_TO_FHIR_SYSTEM,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
# Core
|
|
49
|
+
"R5",
|
|
50
|
+
# R4 ↔ R5
|
|
51
|
+
"r4_to_r5",
|
|
52
|
+
"r5_to_r4",
|
|
53
|
+
"conversion_status",
|
|
54
|
+
# V2 ↔ R5
|
|
55
|
+
"v2_to_r5",
|
|
56
|
+
"r5_to_v2",
|
|
57
|
+
"V2Converter",
|
|
58
|
+
# Registry
|
|
59
|
+
"ALL_R5_RESOURCES",
|
|
60
|
+
"R5_RESOURCES",
|
|
61
|
+
"R4_TO_R5_MAP",
|
|
62
|
+
"V2_SEGMENT_TO_FHIR",
|
|
63
|
+
"V2_MESSAGE_TO_FHIR",
|
|
64
|
+
"V2_DATATYPE_TO_FHIR",
|
|
65
|
+
"V2_TABLE_TO_FHIR_SYSTEM",
|
|
66
|
+
]
|