CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-fhirpy

Async/sync FHIR client for Python providing comprehensive API for CRUD operations over FHIR resources

68

1.07x
Overview
Eval results
Files

search.mddocs/

Search and Query

Advanced FHIR search capabilities with chaining, modifiers, includes, pagination, and complex query building. SearchSets provide a fluent API for building and executing FHIR queries.

Capabilities

Basic Search Operations

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
    """

Advanced Search Features

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
    """

Result Fetching

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
    """

SearchSet Utilities

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
    """

Search Query Builder

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
        """

Usage Examples

Basic Search Operations

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")

Advanced Query Building with SQ

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()

Includes and References

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('*')

Pagination and Result Handling

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")

Complex Search Scenarios

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']

SearchSet Iteration

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-fhirpy

docs

client.md

index.md

references.md

resources.md

search.md

utilities.md

tile.json