-
Notifications
You must be signed in to change notification settings - Fork 28
Bulk FHIR Gen 3 Authorization Tagging #313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
dsafarian
wants to merge
63
commits into
uc-cdis:master
Choose a base branch
from
dsafarian:fhir_transform
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
63 commits
Select commit
Hold shift + click to select a range
fdc70f1
Added cli/fhir_transform.py and transform_utils.py
dsafarian 134df13
Add fhir_transform cli, utils, and tests
dsafarian 92d603e
Remove unnecessary imports
dsafarian 44940a9
Add documentation, format tests, integrate into gen3 cli, add test_da…
dsafarian aab4d54
Fix and add tests, create folder even if output_file path doesn't exist
dsafarian c66e855
Pass all tests, modify multiprocessing to not cause issues with gen3,…
dsafarian 404be39
test md
dsafarian 8899bef
Add fhir.md
dsafarian 2d2e6fe
Merge branch 'uc-cdis:master' into fhir_transform
dsafarian 3f861f6
Black formatting
dsafarian 80f1315
black formatting
dsafarian d8ae042
Fix pull request comments
dsafarian 76c6797
Delete test outputs
dsafarian a34ed6c
Remove setuptools dependency from pyproject.toml
dsafarian d929fd2
Fix pyproject.toml dependencies and poetry.lock
dsafarian 8e0174c
Remove FIXME
dsafarian 6192216
Fix default working directory and directory creation, imports, rename…
dsafarian 6b5f319
Remove test outputs, fix typos, add assertions, change to SHA-256 has…
dsafarian d00ecf5
Fix hash bug
dsafarian 8339418
Add unit test for global authz and fix tmp_path
dsafarian 9cbf8ba
Comment out all parrallelization code
dsafarian 8f5eee5
Remove _resume_run from all code
dsafarian 9cdf886
Fix exception handling
dsafarian 818c537
Fix resource_type check
dsafarian dd2abb2
Use fhirpathpy.compile instead of fhirpathpy.evaluate for speed up.
dsafarian 157eb94
Add check for if output file exists and is not empty for _is_new.
dsafarian d7773f6
Fix poetry dependencies
dsafarian 82e8710
Remove all parallelization code and make fhir import optional in cli
dsafarian 9c42dd7
Add helper function for tag_fhir_resources_with_authz and fix tmp_roo…
dsafarian a9a0418
Black formatting
dsafarian 7b942b0
fix(drsclient): remove dep due to out of date sub-deps, implement DRS…
Avantol13 69279e0
Merge branch 'master' into fhir_transform
Avantol13 df146ee
Update docs/howto/fhir.md
dsafarian ece2a0a
Update fhir.md
dsafarian 3d340b2
Update fhir.md
dsafarian 8b86006
Update fhir.md
dsafarian 50ae4e1
Fix commands for optional fhir import
dsafarian d248015
Fix paths in .config.json for fhir unit test and the pyproject.toml
dsafarian 0591c06
Black formatting
dsafarian 2cb7ec9
Update tests/test_fhir_transform.py
dsafarian 202bfd9
Update gen3/cli/fhir.py
dsafarian 3429568
Add tagger fixture
dsafarian 99fef2d
Add fixture for tagger
dsafarian bc78b45
Update gen3/fhir.py custom hook annotation
dsafarian b27d551
Add more details to fhir.md
dsafarian a4ad290
Add more details to fhir.md
dsafarian d44d5f6
Fix ImportError in cli/__main__.py
dsafarian a2e9e1e
Update gen3/fhir.py
dsafarian d265955
Fix quote style in test_fhir_transform.py
dsafarian eb53cb9
Fix quote style in test_fhir_transform.py
dsafarian eb51c1c
Fix status class tests, remove __init__
dsafarian ae3e632
Fix status class tests, remove __init__
dsafarian de5eab1
Remove pytest argument for test_merge_needed_overlap
dsafarian b2cd806
Add --work_dir flag to cli tests
dsafarian ce83e86
Fix cleanup_fhir_transform_artifacts return and doc string
dsafarian c427e80
Fix/add hint typing and doc string where missing
dsafarian cf86e7e
Change version to 5.0.0 and remove python 3.9 from dependencies and t…
dsafarian 7d6fc69
Make test_chunking, test_transform, test_merge and others independent…
dsafarian 008d713
Remove checking the output file from _is_new
dsafarian 0b1dea0
Make done atomic and write per record
dsafarian 14317fb
Remove split_file and instead use byte ranges to 'chunk'
dsafarian 1197bd6
Update _merge_needed to match the new byte-sized/no-files chunking logic
dsafarian 88c3c7c
Remove chunking test
dsafarian File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| ## FHIR | ||
|
|
||
| This integration aims to enhance the data ingestion capabilities of Gen3 by integrating a Fast Healthcare Interoperability Resources (FHIR) data ingestion tools. FHIR is an important standard for working with Electronic Health Records (EHR) and we have started development of a Gen3 FHIR Proxy service. | ||
|
|
||
| Gen3 is working on adding support for FHIR and these tools will help with data preparation. | ||
|
|
||
|
|
||
| The fhir commands can be invoked as follows | ||
|
|
||
| `gen3 fhir COMMAND [ARGS] [OPTIONS]` | ||
|
|
||
| For a list of commands and options run | ||
|
|
||
| `gen3 fhir --help` | ||
|
|
||
| For example, the following tags the 'Patient.ndjson' file with Gen3 authorization and outputs 'gen3_Patient.ndjson' using the authorization rules from 'config.yaml'. | ||
|
|
||
| `gen3 fhir transform Patient.ndjson gen3_Patient.ndjson config.yaml --batch_size 10000` | ||
|
|
||
| INPUT_FILE: | ||
| There can only be one resource type per NDJSON file. | ||
|
|
||
| OUTPUT_FILE: | ||
| Requires a distinct name/path from the input file to prevent overwriting the input file. | ||
|
|
||
| CONFIG.YAML: | ||
| The authorization configuration file has to be in yaml format and can have multiple conditions, as well as a `global_authz` which overrides all other rules. Conditions use [https://hl7.org/fhirpath/](FHIRPath) syntax. | ||
|
|
||
| A resource matching two rules will throw an error and will require reconfiguration of the YAML file. | ||
|
|
||
| Example rules: | ||
|
|
||
| ```yaml | ||
| rules: | ||
| - resource_type: "Patient" | ||
| condition: "Patient.managingOrganization.reference = 'Organization/site-alpha'" | ||
| authz: "/programs/Alpha/projects/Main" | ||
|
|
||
| #Example with multiple conditions | ||
| - resource_type: "Specimen" | ||
| condition: "Specimen.status = 'available' and Specimen.Type = 'Blood specimen (specimen)'" | ||
| authz: "/programs/Alpha/projects/Biobank" | ||
| ``` | ||
|
|
||
| And example config.yaml file can be found in [fhir_config.yaml](../../tests/test_data/fhir_config.yaml) | ||
| To run the fhir transfrom with synthetic test data: | ||
|
|
||
| `poetry run gen3 -vv fhir transform ./tests/test_data/Patient.ndjson ./test_Patient.ndjson ./tests/test_data/fhir_config.yaml` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| import click | ||
| import os | ||
| import pathlib | ||
| from cdislogging import get_logger | ||
| from gen3.fhir import * | ||
|
|
||
| logging = get_logger(__name__) | ||
|
|
||
|
|
||
| @click.group() | ||
| def fhir(): | ||
| """Commands for FHIR data processing""" | ||
| pass | ||
|
|
||
|
|
||
| @click.command( | ||
| context_settings={"help_option_names": ["-h", "--help"]}, | ||
| help="""Tag Bulk FHIR data with Gen3 compatible authorization tags. | ||
|
|
||
| \b | ||
| input_file (str): Input .ndjson file with Bulk FHIR data, MUST be one resource type per file | ||
| output_file (str): Output file name, also an .ndjson file | ||
| config (str): .yaml file with authorization rules, see docs/howto/fhir.md for more details on formatting | ||
| """, | ||
| ) | ||
| @click.argument( | ||
| "input_file", | ||
| type=click.Path(exists=True, dir_okay=False, readable=True), | ||
| metavar="input_file", | ||
| ) | ||
| @click.argument( | ||
| "output_file", type=click.Path(dir_okay=False, writable=True), metavar="output_file" | ||
| ) | ||
| @click.argument( | ||
| "config", | ||
| type=click.Path(exists=True, dir_okay=False, readable=True), | ||
| metavar="config", | ||
| ) | ||
| @click.option( | ||
| "--work_dir", | ||
| type=click.Path(), | ||
| metavar="work_dir", | ||
| help=f"Specify which working directory to clean, if not specified the default ({DEFAULT_WORK_DIR}) will be used. Can also be set as an environment variable: GEN3_FHIR_WORK_DIR", | ||
| ) | ||
| @click.option( | ||
| "-b", | ||
| "--batch_size", | ||
| type=click.IntRange(min=1), | ||
| default=10000, | ||
| show_default=True, | ||
| metavar="batch_size", | ||
| help="batch size for chunking", | ||
| ) | ||
| @click.option( | ||
| "--force", | ||
| is_flag=True, | ||
| help="Remove all intermediate files for this run before exiting even if run crashes", | ||
| ) | ||
| def cli( | ||
| input_file: str | os.PathLike[str], | ||
| output_file: str | os.PathLike[str], | ||
| config: str | os.PathLike[str], | ||
| work_dir: str | os.PathLike[str] | None, | ||
| batch_size: int, | ||
| force: bool, | ||
| ): | ||
| """ | ||
| CLI implementation of tag_fhir_resources_with_authz. | ||
|
|
||
| Args: | ||
| input_file (str): Input .ndjson file | ||
| output_file (str): Output file name | ||
| config (str): .yaml file with authorization rules | ||
| work_dir (str): Working directory to save intermediate files for each run | ||
| batch_size (int): number of lines per chunk | ||
| force (bool): remove all intermediate files for this run before exiting even if it crashes | ||
| """ | ||
| tag_fhir_resources_with_authz( | ||
| input_file=input_file, | ||
| output_file=output_file, | ||
| config=config, | ||
| batch_size=batch_size, | ||
| work_dir=work_dir, | ||
| force=force, | ||
| ) | ||
|
|
||
|
|
||
| @click.command( | ||
| context_settings={"help_option_names": ["-h", "--help"]}, | ||
| help="Remove all intermediate files in the tmp folder from previous runs", | ||
| ) | ||
| @click.option( | ||
| "--work_dir", | ||
| type=click.Path(), | ||
| metavar="work_dir", | ||
| help=f"Specify which working directory to clean, if not specified the default ({DEFAULT_WORK_DIR}) will be cleaned. Can also be set as an environment variable: GEN3_FHIR_WORK_DIR", | ||
| ) | ||
| @click.option( | ||
| "--dry-run", | ||
| is_flag=True, | ||
| help="Report what would be deleted without deleting the files", | ||
| ) | ||
| @click.option( | ||
| "--force", | ||
| is_flag=True, | ||
| help="Remove temporary directory ignoring status of each directory", | ||
| ) | ||
| def cleanup(work_dir, dry_run: bool, force: bool): | ||
| """ | ||
| Remove all intermediate files in the tmp folder from previous runs | ||
|
|
||
| Args: | ||
| work_dir (str): Working directory to save intermediate files for each run | ||
| dry_run (bool): If True, list the files that would be removed, but not actually remove them | ||
| force (bool): Delete all intermediate directories disregarding the status | ||
| """ | ||
|
|
||
| cleanup_fhir_transform_artifacts(work_dir=work_dir, dry_run=dry_run, force=force) | ||
|
|
||
|
|
||
| fhir.add_command(cli, name="transform") | ||
| fhir.add_command(cleanup, name="cleanup") |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.