Skip to content

Commit 6aefdbc

Browse files
committed
Reapply "146 switch from poetry to uv"
This reverts commit 70ee682.
1 parent b60aea7 commit 6aefdbc

6 files changed

Lines changed: 3533 additions & 66 deletions

File tree

.markdownlint-cli2.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
config:
2+
MD013: false # disable line length rule

.pre-commit-config.yaml

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# See https://gitlab.uk-essen.de/ship-ai/pre-commit-hooks for the newest version
1+
# See https://gitlab.uk-essen.de/ship-ai/templates/pre-commit-hooks
22

33
repos:
44
- repo: https://github.com/charliermarsh/ruff-pre-commit
5-
rev: v0.11.6
5+
rev: v0.14.14
66
hooks:
77
- id: ruff
88
args: [--fix]
@@ -11,7 +11,7 @@ repos:
1111
exclude: examples
1212

1313
- repo: https://github.com/pre-commit/mirrors-mypy
14-
rev: v1.15.0
14+
rev: v1.19.1
1515
hooks:
1616
- id: mypy
1717
language_version: python3.10
@@ -25,13 +25,35 @@ repos:
2525
exclude: node_modules
2626

2727
- repo: https://github.com/tox-dev/pyproject-fmt
28-
rev: v2.5.1
28+
rev: v2.12.0
2929
hooks:
3030
- id: pyproject-fmt
3131
types: [toml]
3232

33+
- repo: https://github.com/DavidAnson/markdownlint-cli2
34+
rev: v0.20.0
35+
hooks:
36+
- id: markdownlint-cli2
37+
args: [--fix]
38+
39+
- repo: https://github.com/codespell-project/codespell
40+
rev: v2.4.1
41+
hooks:
42+
- id: codespell
43+
types: [markdown]
44+
45+
- repo: local
46+
hooks:
47+
- id: export-requirements
48+
name: Export requirements from uv
49+
entry: uv pip compile
50+
args: ["pyproject.toml", "--output-file", "requirements.txt"]
51+
language: system
52+
pass_filenames: false
53+
always_run: true
54+
3355
- repo: https://github.com/pre-commit/pre-commit-hooks
34-
rev: v5.0.0
56+
rev: v6.0.0
3557
hooks:
3658
- id: end-of-file-fixer
3759
- id: check-merge-conflict

README.md

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# FHIR-PYrate
2+
13
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
24
[![Supported Python version](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/release/python-31011/)
35
[![Stable Version](https://img.shields.io/pypi/v/fhir-pyrate?label=stable)](https://pypi.org/project/fhir-pyrate/)
@@ -13,9 +15,10 @@ pandas DataFrames. Want to use R instead? Try out [fhircrackr](https://github.co
1315

1416
**If you use this package, please cite:**
1517

16-
Hosch, R., Baldini, G., Parmar, V. et al. FHIR-PYrate: a data science friendly Python package to query FHIR servers. BMC Health Serv Res 23, 734 (2023). https://doi.org/10.1186/s12913-023-09498-1
18+
Hosch, R., Baldini, G., Parmar, V. et al. FHIR-PYrate: a data science friendly Python package to query FHIR servers. BMC Health Serv Res 23, 734 (2023). <https://doi.org/10.1186/s12913-023-09498-1>
1719

1820
There are four main classes:
21+
1922
* [Ahoy](https://github.com/UMEssen/FHIR-PYrate/blob/main/fhir_pyrate/ahoy.py): Authenticate on the FHIR API
2023
([Example 1](https://github.com/UMEssen/FHIR-PYrate/blob/main/examples/1-simple-json-to-df.ipynb),
2124
[2](https://github.com/UMEssen/FHIR-PYrate/blob/main/examples/2-condition-to-imaging-study.ipynb)),
@@ -42,73 +45,88 @@ problems with the authentication (or anything else really), please just create a
4245
Table of Contents:
4346

4447
* [Install](https://github.com/UMEssen/FHIR-PYrate/#install)
45-
* [Either Pip](https://github.com/UMEssen/FHIR-PYrate/#either-pip)
46-
* [Or Within Poetry](https://github.com/UMEssen/FHIR-PYrate/#or-within-poetry)
48+
* [Either Pip](https://github.com/UMEssen/FHIR-PYrate/#either-pip)
49+
* [Or Within Poetry](https://github.com/UMEssen/FHIR-PYrate/#or-within-poetry)
4750
* [Run Tests](https://github.com/UMEssen/FHIR-PYrate/#run-tests)
4851
* [Explanations &amp; Examples](https://github.com/UMEssen/FHIR-PYrate/#explanations--examples)
49-
* [Ahoy](https://github.com/UMEssen/FHIR-PYrate/#ahoy)
50-
* [Pirate](https://github.com/UMEssen/FHIR-PYrate/#pirate)
51-
* [sail_through_search_space](https://github.com/UMEssen/FHIR-PYrate/#sail_through_search_space)
52-
* [trade_rows_for_bundles](https://github.com/UMEssen/FHIR-PYrate/#trade_rows_for_bundles)
53-
* [bundles_to_dataframe](https://github.com/UMEssen/FHIR-PYrate/#bundles_to_dataframe)
54-
* [***_dataframe](https://github.com/UMEssen/FHIR-PYrate/#_dataframe)
55-
* [Miner](https://github.com/UMEssen/FHIR-PYrate/#miner)
56-
* [DicomDownloader](https://github.com/UMEssen/FHIR-PYrate/#dicomdownloader)
52+
* [Ahoy](https://github.com/UMEssen/FHIR-PYrate/#ahoy)
53+
* [Pirate](https://github.com/UMEssen/FHIR-PYrate/#pirate)
54+
* [sail_through_search_space](https://github.com/UMEssen/FHIR-PYrate/#sail_through_search_space)
55+
* [trade_rows_for_bundles](https://github.com/UMEssen/FHIR-PYrate/#trade_rows_for_bundles)
56+
* [bundles_to_dataframe](https://github.com/UMEssen/FHIR-PYrate/#bundles_to_dataframe)
57+
* [***_dataframe](https://github.com/UMEssen/FHIR-PYrate/#_dataframe)
58+
* [Miner](https://github.com/UMEssen/FHIR-PYrate/#miner)
59+
* [DicomDownloader](https://github.com/UMEssen/FHIR-PYrate/#dicomdownloader)
5760
* [Contributing](https://github.com/UMEssen/FHIR-PYrate/#contributing)
5861
* [Authors and acknowledgment](https://github.com/UMEssen/FHIR-PYrate/#authors-and-acknowledgment)
5962
* [License](https://github.com/UMEssen/FHIR-PYrate/#license)
6063
* [Project status](https://github.com/UMEssen/FHIR-PYrate/#project-status)
6164

62-
6365
## Install
6466

6567
### Either Pip
68+
6669
The package can be installed using PyPi
70+
6771
```bash
6872
pip install fhir-pyrate
6973
```
74+
7075
or using GitHub (always the newest version).
76+
7177
```bash
7278
pip install git+https://github.com/UMEssen/FHIR-PYrate.git
7379
```
7480

7581
These two commands only install the packages needed for **Pirate**. If you also want to use the **Miner** or the **DicomDownloader**, then you need to install them as extra dependencies with
82+
7683
```bash
7784
pip install "fhir-pyrate[miner]" # only for miner
7885
pip install "fhir-pyrate[downloader]" # only for downloader
7986
pip install "fhir-pyrate[all]" # for both
8087
```
8188

8289
### Or Within Poetry
90+
8391
We can also use poetry for this same purpose. Using PyPi we need to run the following commands.
92+
8493
```bash
8594
poetry add fhir-pyrate
8695
poetry install
8796
```
97+
8898
Whereas to add it from GitHub, we have different options, because until recently
8999
[poetry used to exclusively install from the master branch](https://github.com/python-poetry/poetry/issues/3366).
90100

91101
Poetry 1.2.0a2+:
102+
92103
```bash
93104
poetry add git+https://github.com/UMEssen/FHIR-PYrate.git
94105
poetry install
95106
```
107+
96108
For the previous versions you need to add the following line to your `pyproject.toml` file:
109+
97110
```bash
98111
fhir-pyrate = {git = "https://github.com/UMEssen/FHIR-PYrate.git", branch = "main"}
99112
```
113+
100114
and then run
115+
101116
```bash
102117
poetry lock
103118
```
104119

105120
Also in poetry, the above only installs the packages for **Pirate**. If you also want to use the **Miner** or the **DicomDownloader**, then you need to install them as extra dependencies with
121+
106122
```bash
107123
poetry add "fhir-pyrate[miner]" # only for miner
108124
poetry add "fhir-pyrate[downloader]" # only for downloader
109125
poetry add "fhir-pyrate[all]" # for both
110126
```
127+
111128
or by adding the following to your `pyproject.toml` file:
129+
112130
```bash
113131
fhir-pyrate = {git = "https://github.com/UMEssen/FHIR-PYrate.git", branch = "main", extras = ["all"]}
114132
```
@@ -176,6 +194,7 @@ search = Pirate(
176194
```
177195

178196
The Pirate functions do one of three things:
197+
179198
1. They run the query and collect the resources and store them in a generator of bundles.
180199
* `steal_bundles`: single process, no timespan to specify
181200
* `sail_through_search_space`: multiprocess, divide&conquer with many smaller timespans
@@ -197,7 +216,6 @@ The Pirate functions do one of three things:
197216
| sail_through_search_space_to_dataframe | 3 | Yes | No | DataFrame |
198217
| trade_rows_for_dataframe | 3 | Yes | Yes | DataFrame |
199218

200-
201219
**CACHING**: It is also possible to cache the bundles using the `cache_folder` parameter.
202220
This unfortunately does not currently work with multiprocessing, but saves a lot of time if you
203221
need to download a lot of data and you are always doing the same requests.
@@ -276,7 +294,8 @@ is the column where the values that we want to search for are stored.
276294
Additionally, a system can be used to better identify the constraints of the DataFrame.
277295
For example, let us assume that we have a column of the DataFrame (called `loinc_code` that
278296
contains a bunch of different LOINC codes. Our `df_constraints` could look as follows:
279-
```
297+
298+
```python
280299
df_constraints={"code": ("http://loinc.org", "loinc_code")}
281300
```
282301

@@ -290,10 +309,12 @@ converted to a `DataFrame` using this function.
290309

291310
The `bundles_to_dataframe` has three options on how to handle and extract the relevant information
292311
from the bundles:
312+
293313
1. Extract everything, in this case you can use the
294314
[`flatten_data`](https://github.com/UMEssen/FHIR-PYrate/blob/main/fhir_pyrate/util/bundle_processing_templates.py)
295315
function, which is already the default for `process_function`, so you do not actually need to
296316
specify anything.
317+
297318
```python
298319
# Create bundles with Pirate
299320
search = ...
@@ -303,10 +324,12 @@ df = search.bundles_to_dataframe(
303324
bundles=bundles,
304325
)
305326
```
306-
2. Use a processing function where you define exactly which attributes are needed by iterating
327+
328+
1. Use a processing function where you define exactly which attributes are needed by iterating
307329
through the entries and selecting the elements. The values that will be added to the
308330
dictionary represent the columns of the DataFrame. For an example of when it might make sense
309331
to do this, check [Example 3](https://github.com/UMEssen/FHIR-PYrate/blob/main/examples/3-patients-for-condition.ipynb).
332+
310333
```python
311334
from typing import List, Dict
312335
from fhir_pyrate.util.fhirobj import FHIRObj
@@ -331,12 +354,14 @@ df = search.bundles_to_dataframe(
331354
process_function=get_diagnostic_text,
332355
)
333356
```
334-
3. Extract only part of the information using the `fhir_paths` argument. Here you can put a list
357+
358+
1. Extract only part of the information using the `fhir_paths` argument. Here you can put a list
335359
of string that follow the [FHIRPath](https://hl7.org/fhirpath/) standard. For this purpose, we
336360
use the [fhirpath-py](https://github.com/beda-software/fhirpath-py) package, which uses the
337361
[antr4](https://github.com/antlr/antlr4) parser. Additionally, you can use tuples like `(key,
338362
fhir_path)`, where `key` will be the name of the column the information derived from that
339363
FHIRPath will be stored.
364+
340365
```python
341366
# Create bundles with Pirate
342367
search = ...
@@ -347,6 +372,7 @@ df = search.bundles_to_dataframe(
347372
fhir_paths=["id", ("code", "code.coding"), ("identifier", "identifier[0].code")],
348373
)
349374
```
375+
350376
**NOTE 1 on FHIR paths**: The standard also allows some primitive math operations such as modulus
351377
(`mod`) or integer division (`div`), and this may be problematic if there are fields of the
352378
resource that use these terms as attributes.
@@ -357,7 +383,8 @@ instead (as in 2.).
357383
**NOTE 2 on FHIR paths**: Since it is possible to specify the column name with a tuple
358384
`(key, fhir_path)`, it is important to know that if a key is used multiple times for different
359385
pieces of information but for the same resource, the field will be only filled with the first
360-
occurence that is not None.
386+
occurrence that is not None.
387+
361388
```python
362389
df = search.steal_bundles_to_dataframe(
363390
resource_type="DiagnosticReport",
@@ -385,6 +412,7 @@ df = search.steal_bundles_to_dataframe(
385412
```
386413

387414
#### [`***_dataframe`](https://github.com/UMEssen/FHIR-PYrate/blob/main/fhir_pyrate/pirate.py)
415+
388416
The `steal_bundles_to_dataframe`, `sail_through_search_space_to_dataframe` and `trade_rows_for_dataframe`
389417
are facade functions which retrieve the bundles and then run `bundles_to_dataframe`.
390418

@@ -404,6 +432,7 @@ More on that in the following section.
404432

405433
Not all FHIR servers allow this (at least not the public ones that we have tried),
406434
but it is also possible to obtain multiple resources with just one query:
435+
407436
```python
408437
search = ...
409438
result_dfs = search.steal_bundles_to_dataframe(
@@ -431,6 +460,7 @@ result_dfs = search.steal_bundles_to_dataframe(
431460
num_pages=1,
432461
)
433462
```
463+
434464
In this case, a dictionary of DataFrames is returned, where the keys are the resource types.
435465
You can then select the single dictionary by doing `result_dfs["ImagingStudy"]`
436466
or `result_dfs["Patient"]`.
@@ -452,14 +482,9 @@ such that only the ones containing
452482
the actual resource name are kept if the resource name is specified in the path,
453483
and that a column full of `None`s is obtained in case no resource type is specified.
454484

455-
456485
### [Miner](https://github.com/UMEssen/FHIR-PYrate/blob/main/fhir_pyrate/miner.py)
457486

458-
<br />
459-
<div align="center">
460-
<img src="https://raw.githubusercontent.com/UMEssen/FHIR-PYrate/main/images/miner.svg" alt="Logo" width="718" height="230">
461-
</div>
462-
<br />
487+
![FHIR-PYrate Logo](https://raw.githubusercontent.com/UMEssen/FHIR-PYrate/main/images/miner.svg)
463488

464489
The **Miner** takes a DataFrame and searches it for a particular regular expression
465490
with the help of [SpaCy](https://spacy.io/).
@@ -571,13 +596,15 @@ request. You can also simply open an issue with the tag "enhancement".
571596

572597
This package was developed by the [SHIP-AI group at the Institute for Artificial Intelligence in Medicine](https://ship-ai.ikim.nrw/).
573598

574-
- [goku1110](https://github.com/goku1110): initial idea, development, logo & figures
575-
- [giuliabaldini](https://github.com/giuliabaldini): development, tests, new features
599+
* [goku1110](https://github.com/goku1110): initial idea, development, logo & figures
600+
* [giuliabaldini](https://github.com/giuliabaldini): development, tests, new features
576601

577602
We would like to thank [razorx89](https://github.com/razorx89), [butterpear](https://github.com/butterpear), [vkyprmr](https://github.com/vkyprmr), [Wizzzard93](https://github.com/Wizzzard93), [karzideh](https://github.com/karzideh) and [luckfamousa](https://github.com/luckfamousa) for their input, time and effort.
578603

579604
## License
605+
580606
This project is licenced under the [MIT Licence](LICENSE).
581607

582608
## Project status
609+
583610
The project is in active development.

0 commit comments

Comments
 (0)