Metadata-Version: 2.1
Name: fhir-types
Version: 0.2.4
Summary: Types for FHIR Resources
Author: Anthem Inc
License: Apache
Keywords: FHIR
Platform: UNKNOWN
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE.md

# Python Typings For FHIR

The FHIR Types package exports types declared using the [typing](https://docs.python.org/3/library/typing.html) library. This provides type checking support when creating dictionaries of FHIR objects in Python.

## Installation

### Installing from Pypi (recommended)

We recommend you first use a virtual environment and activate it in your shell.

`pip install fhir-types`

### Installing from source
1. Clone this repository
1. Change to the package root directory
1. Run the `pipenv install --dev  --deploy` command to create and install in a virtual environment

```bash
% pipenv install --dev --deploy
Creating a virtualenv for this project...
Pipfile: /fhir-types/Pipfile
Using /usr/local/bin/python3 (3.9.7) to create virtualenv...
. . .
```

If you want to install globally run `pip install .`, outside of a virtual environment.

### Verify the installation

Verify the installation with `pipenv run almake test`.

```bash
% pipenv run almake test
python -m black --check .
All done! ✨ 🍰 ✨
702 files would be left unchanged.
python -m isort --check --df .
. . .
```

Or, if you have `make` installed:

```bash
% pipenv run make test
<same output as shown above>
```

## Usage
This project was developed using [mypy](https://github.com/python/mypy) for type checking.

### Example

Consider these two FHIR JSON dictionaries.

```python
# myfile.py

from fhir_types import FHIR_Patient

# This is a valid patient dictionary
patient: FHIR_Patient = {
    "resourceType": "Patient",
    "gender": "female",
    "name": [
        {
            "use": "official",
            "family": "Johnson",
            "given": ["Jennifer"],
            "prefix": ["Mrs."],
        }
    ]
}

# This is an invalid patient dictionary
invalid_patient: FHIR_Patient = {
    "resourceType": "PPPPatient", # error 1
    "gender": "female123",  # error 2
    "name": [
        {
            "123use": "official", # error 3
            "family": "Johnson",
            "given": ["Jennifer"],
            "prefix": ["Mrs."],
        }
    ]
}
```

After installing `mypy` with `pip`, running `mypy myfile.py` will display the errors in the second (invalid) structure. 

It is good practice to set up your IDE (such as VS Code) to use `mypy` for linting as you work.

## Issues
The Types located in the fhir_types directory are generated from the official `fhir.schema.json` provided by FHIR.

This data stucture is quite large with and contains cyclical relationships. Unfortunately, `mypy` does not handle cyclical relationships and has an open issue [here](https://github.com/python/mypy/issues/731). We added a workaround that reduces the type checking capabilities for certain properties in some classes.

All properties that point to any of the following classes are given an [Any](https://mypy.readthedocs.io/en/stable/kinds_of_types.html#the-any-type) type because these lead to circular references. These were found by repeatedly running the `mypy` command.

```bash
CIRCULAR_REFERENCES = {
    "Extension",
    "Identifier",
    "ResourceList",
    "QuestionnaireResponse_Answer",
    "GraphDefinition_Link",
    "ExampleScenario_Process",
    "ExampleScenario_Alternative",
}
```

The other case is when a property points back to a parent class.

```python
from fhir_types import FHIR_Questionnaire_Item

FHIR_Questionnaire_Item = TypedDict("FHIR_Questionnaire_Item", {
    "id": "123",
    item: List[Any] # This used to be FHIR_Questionnaire_Item but was changed to Any
})
```

Here, full type checking can be accomplished by creating two separate dictionaries and then combining them. For example:

```python
from fhir_types import FHIR_Extension, FHIR_Patient

extension: FHIR_Extension = {
    "valueAddress": {
        "city": "Springfield",
        "state": "Massachusetts",
        "country": "US"
    }
}

patient: FHIR_Patient = {
    "gender": "male",
    "extension": [extension]
}
```


