Async/sync FHIR client for Python providing comprehensive API for CRUD operations over FHIR resources
68
Advanced FHIR search capabilities with chaining, modifiers, includes, pagination, and complex query building. SearchSets provide a fluent API for building and executing FHIR queries.
Core search functionality for building and executing FHIR queries.
def search(self, **params) -> FHIRSearchSet:
"""
Add search parameters to the query.
Parameters:
- **params: Search parameters as keyword arguments
Returns:
New SearchSet instance with parameters added
"""
def limit(self, count: int) -> FHIRSearchSet:
"""
Set maximum number of results to return.
Parameters:
- count: Maximum result count
Returns:
New SearchSet instance with limit applied
"""
def sort(self, *args) -> FHIRSearchSet:
"""
Set sort parameters for results.
Parameters:
- *args: Sort fields, prefix with '-' for descending order
Returns:
New SearchSet instance with sorting applied
"""
def elements(self, *args, exclude=False) -> FHIRSearchSet:
"""
Specify which elements to include or exclude in results.
Parameters:
- *args: Element names to include/exclude
- exclude: If True, exclude specified elements; if False, include only specified elements
Returns:
New SearchSet instance with element selection
"""Include, revinclude, and _has parameter support for complex queries.
def include(
self,
resource_type: str,
attr: str = None,
*,
iterate: bool = False
) -> FHIRSearchSet:
"""
Add _include parameter to include referenced resources.
Parameters:
- resource_type: Resource type to include
- attr: Reference parameter name (required unless resource_type is '*')
- iterate: Whether to apply :iterate modifier
Returns:
New SearchSet instance with include added
"""
def revinclude(
self,
resource_type: str,
attr: str = None,
*,
iterate: bool = False
) -> FHIRSearchSet:
"""
Add _revinclude parameter to include referencing resources.
Parameters:
- resource_type: Resource type that references this type
- attr: Reference parameter name (required unless resource_type is '*')
- iterate: Whether to apply :iterate modifier
Returns:
New SearchSet instance with revinclude added
"""
def has(self, *args, **kwargs) -> FHIRSearchSet:
"""
Add _has parameter for reverse chaining.
Parameters:
- *args: Positional _has parameters
- **kwargs: Named _has parameters
Returns:
New SearchSet instance with _has parameter added
"""Methods for executing queries and retrieving results.
async def count(self) -> int:
"""
Get total count of matching resources.
Returns:
Total number of resources matching the query
"""
async def first(self) -> FHIRResource:
"""
Get the first result from the query.
Returns:
First matching resource or None if no results
"""
async def get(self) -> FHIRResource:
"""
Get exactly one result from the query.
Returns:
Single matching resource
Raises:
- ResourceNotFound: If no resources match
- MultipleResourcesFound: If multiple resources match
"""
async def fetch(self) -> list:
"""
Fetch all results from current page.
Returns:
List of resources from current page
"""
async def fetch_all(self) -> list:
"""
Fetch all results from all pages.
Returns:
List of all matching resources across all pages
"""
async def fetch_raw(self) -> dict:
"""
Fetch raw Bundle response from server.
Returns:
Raw FHIR Bundle dict
"""Helper methods for working with search sets.
def clone(self) -> FHIRSearchSet:
"""
Create a copy of the SearchSet.
Returns:
New SearchSet instance with same parameters
"""
async def __aiter__(self):
"""
Async iteration support for AsyncFHIRSearchSet.
Allows using 'async for' to iterate through all search results,
automatically handling pagination.
Yields:
Individual resources from search results
"""Advanced query building utilities for complex search parameters.
def SQ(*args, **kwargs) -> dict:
"""
Build search query parameters with advanced syntax support.
Supports:
- Chained parameters: patient__Patient__name='John'
- Search modifiers: name__contains='test'
- Date comparisons: date__ge='2020-01-01'
- Multiple values: status__in=['active', 'inactive']
Returns:
Dict of properly formatted search parameters
"""
class Raw:
def __init__(self, **kwargs):
"""
Wrapper for raw parameter values that should not be transformed.
Parameters:
- **kwargs: Raw parameter key-value pairs
"""import asyncio
from fhirpy import AsyncFHIRClient
async def basic_search():
client = AsyncFHIRClient('https://hapi.fhir.org/baseR4')
# Simple search
patients = client.resources('Patient').search(family='Smith')
results = await patients.fetch()
# Search with multiple parameters
patients = client.resources('Patient').search(
family='Smith',
given='John',
active=True
)
# Limit results and sort
recent_patients = (client.resources('Patient')
.search(active=True)
.sort('-_lastUpdated')
.limit(10))
results = await recent_patients.fetch()
# Get total count
total = await patients.count()
print(f"Found {total} patients")from fhirpy.base.searchset import SQ
async def advanced_queries():
client = AsyncFHIRClient('https://hapi.fhir.org/baseR4')
# Chained search - find patients with observations
query = SQ(patient__Patient__name='John')
observations = client.resources('Observation').search(**query)
# Search modifiers
query = SQ(
name__contains='John', # :contains modifier
birthdate__ge='1990-01-01', # greater than or equal
gender__not='unknown' # :not modifier
)
patients = client.resources('Patient').search(**query)
# Multiple values
query = SQ(status__in=['active', 'inactive'])
patients = client.resources('Patient').search(**query)
# Complex chained parameters
query = SQ(
patient__Patient__general_practitioner__Organization__name='Hospital'
)
observations = client.resources('Observation').search(**query)
results = await observations.fetch()async def include_examples():
client = AsyncFHIRClient('https://hapi.fhir.org/baseR4')
# Include patient data with observations
observations = (client.resources('Observation')
.search(code='55284-4') # Blood pressure
.include('Patient', 'subject'))
bundle = await observations.fetch_raw()
# Bundle contains both observations and referenced patients
# Reverse include - get patients with their observations
patients = (client.resources('Patient')
.search(active=True)
.revinclude('Observation', 'subject')
.limit(5))
results = await patients.fetch_all()
# Include with iteration
encounters = (client.resources('Encounter')
.include('Patient', 'subject', iterate=True)
.include('Organization', 'serviceProvider'))
# Wildcard includes
encounters = client.resources('Encounter').include('*')async def pagination_example():
client = AsyncFHIRClient('https://hapi.fhir.org/baseR4')
# Page through results
patients = client.resources('Patient').limit(50)
page1 = await patients.fetch()
print(f"Page 1: {len(page1)} patients")
# Get all results across all pages
all_patients = await patients.fetch_all()
print(f"Total patients: {len(all_patients)}")
# Get count without fetching data
total_count = await patients.count()
print(f"Total count: {total_count}")
# Get single result safely
try:
specific_patient = await (client.resources('Patient')
.search(identifier='12345')
.get())
except ResourceNotFound:
print("Patient not found")
except MultipleResourcesFound:
print("Multiple patients found with same identifier")async def complex_search():
client = AsyncFHIRClient('https://hapi.fhir.org/baseR4')
# Find observations for patients in specific organization
query = SQ(
subject__Patient__organization='Organization/123',
code__text__contains='blood',
date__ge='2023-01-01',
date__lt='2024-01-01'
)
observations = (client.resources('Observation')
.search(**query)
.include('Patient', 'subject')
.include('Practitioner', 'performer')
.sort('-date')
.limit(100))
# Use _has for reverse chaining
patients_with_conditions = (client.resources('Patient')
.has('Condition', 'subject', code='diabetes'))
# Element selection for performance
patients_summary = (client.resources('Patient')
.search(active=True)
.elements('id', 'name', 'birthDate')
.limit(1000))
# Combine multiple techniques
comprehensive_search = (client.resources('Encounter')
.search(status='finished')
.include('Patient', 'subject')
.revinclude('Observation', 'encounter')
.has('Condition', 'encounter',
category='problem-list-item')
.sort('-date')
.limit(20))
results = await comprehensive_search.fetch_raw()
# Process bundle entries
encounters = [entry['resource'] for entry in results['entry']
if entry['resource']['resourceType'] == 'Encounter']
patients = [entry['resource'] for entry in results['entry']
if entry['resource']['resourceType'] == 'Patient']
observations = [entry['resource'] for entry in results['entry']
if entry['resource']['resourceType'] == 'Observation']async def iteration_example():
client = AsyncFHIRClient('https://hapi.fhir.org/baseR4')
# Async iteration over search results
patients = client.resources('Patient').search(active=True)
async for patient in patients:
print(f"Patient: {patient.get_by_path('name.0.family')}")
# Process each patient individually
if patient.get('gender') == 'female':
# Do something with female patients
pass
# Clone and modify search sets
base_search = client.resources('Patient').search(active=True)
male_patients = base_search.clone().search(gender='male')
female_patients = base_search.clone().search(gender='female')
male_count = await male_patients.count()
female_count = await female_patients.count()
print(f"Male: {male_count}, Female: {female_count}")Install with Tessl CLI
npx tessl i tessl/pypi-fhirpyevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10