Skip to content

Commit f7a1a74

Browse files
authored
Merge pull request #148 from UMEssen/revert-147-146-switch-from-poetry-to-uv
Revert "146 switch from poetry to uv"
2 parents 3f86567 + 70ee682 commit f7a1a74

6 files changed

Lines changed: 66 additions & 3533 deletions

File tree

.markdownlint-cli2.yaml

Lines changed: 0 additions & 2 deletions
This file was deleted.

.pre-commit-config.yaml

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

33
repos:
44
- repo: https://github.com/charliermarsh/ruff-pre-commit
5-
rev: v0.14.14
5+
rev: v0.11.6
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.19.1
14+
rev: v1.15.0
1515
hooks:
1616
- id: mypy
1717
language_version: python3.10
@@ -25,35 +25,13 @@ repos:
2525
exclude: node_modules
2626

2727
- repo: https://github.com/tox-dev/pyproject-fmt
28-
rev: v2.12.0
28+
rev: v2.5.1
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-
5533
- repo: https://github.com/pre-commit/pre-commit-hooks
56-
rev: v6.0.0
34+
rev: v5.0.0
5735
hooks:
5836
- id: end-of-file-fixer
5937
- id: check-merge-conflict

README.md

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

1614
**If you use this package, please cite:**
1715

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

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

4744
* [Install](https://github.com/UMEssen/FHIR-PYrate/#install)
48-
* [Either Pip](https://github.com/UMEssen/FHIR-PYrate/#either-pip)
49-
* [Or Within Poetry](https://github.com/UMEssen/FHIR-PYrate/#or-within-poetry)
45+
* [Either Pip](https://github.com/UMEssen/FHIR-PYrate/#either-pip)
46+
* [Or Within Poetry](https://github.com/UMEssen/FHIR-PYrate/#or-within-poetry)
5047
* [Run Tests](https://github.com/UMEssen/FHIR-PYrate/#run-tests)
5148
* [Explanations &amp; Examples](https://github.com/UMEssen/FHIR-PYrate/#explanations--examples)
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)
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)
6057
* [Contributing](https://github.com/UMEssen/FHIR-PYrate/#contributing)
6158
* [Authors and acknowledgment](https://github.com/UMEssen/FHIR-PYrate/#authors-and-acknowledgment)
6259
* [License](https://github.com/UMEssen/FHIR-PYrate/#license)
6360
* [Project status](https://github.com/UMEssen/FHIR-PYrate/#project-status)
6461

62+
6563
## Install
6664

6765
### Either Pip
68-
6966
The package can be installed using PyPi
70-
7167
```bash
7268
pip install fhir-pyrate
7369
```
74-
7570
or using GitHub (always the newest version).
76-
7771
```bash
7872
pip install git+https://github.com/UMEssen/FHIR-PYrate.git
7973
```
8074

8175
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-
8376
```bash
8477
pip install "fhir-pyrate[miner]" # only for miner
8578
pip install "fhir-pyrate[downloader]" # only for downloader
8679
pip install "fhir-pyrate[all]" # for both
8780
```
8881

8982
### Or Within Poetry
90-
9183
We can also use poetry for this same purpose. Using PyPi we need to run the following commands.
92-
9384
```bash
9485
poetry add fhir-pyrate
9586
poetry install
9687
```
97-
9888
Whereas to add it from GitHub, we have different options, because until recently
9989
[poetry used to exclusively install from the master branch](https://github.com/python-poetry/poetry/issues/3366).
10090

10191
Poetry 1.2.0a2+:
102-
10392
```bash
10493
poetry add git+https://github.com/UMEssen/FHIR-PYrate.git
10594
poetry install
10695
```
107-
10896
For the previous versions you need to add the following line to your `pyproject.toml` file:
109-
11097
```bash
11198
fhir-pyrate = {git = "https://github.com/UMEssen/FHIR-PYrate.git", branch = "main"}
11299
```
113-
114100
and then run
115-
116101
```bash
117102
poetry lock
118103
```
119104

120105
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-
122106
```bash
123107
poetry add "fhir-pyrate[miner]" # only for miner
124108
poetry add "fhir-pyrate[downloader]" # only for downloader
125109
poetry add "fhir-pyrate[all]" # for both
126110
```
127-
128111
or by adding the following to your `pyproject.toml` file:
129-
130112
```bash
131113
fhir-pyrate = {git = "https://github.com/UMEssen/FHIR-PYrate.git", branch = "main", extras = ["all"]}
132114
```
@@ -194,7 +176,6 @@ search = Pirate(
194176
```
195177

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

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

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

310291
The `bundles_to_dataframe` has three options on how to handle and extract the relevant information
311292
from the bundles:
312-
313293
1. Extract everything, in this case you can use the
314294
[`flatten_data`](https://github.com/UMEssen/FHIR-PYrate/blob/main/fhir_pyrate/util/bundle_processing_templates.py)
315295
function, which is already the default for `process_function`, so you do not actually need to
316296
specify anything.
317-
318297
```python
319298
# Create bundles with Pirate
320299
search = ...
@@ -324,12 +303,10 @@ df = search.bundles_to_dataframe(
324303
bundles=bundles,
325304
)
326305
```
327-
328-
1. Use a processing function where you define exactly which attributes are needed by iterating
306+
2. Use a processing function where you define exactly which attributes are needed by iterating
329307
through the entries and selecting the elements. The values that will be added to the
330308
dictionary represent the columns of the DataFrame. For an example of when it might make sense
331309
to do this, check [Example 3](https://github.com/UMEssen/FHIR-PYrate/blob/main/examples/3-patients-for-condition.ipynb).
332-
333310
```python
334311
from typing import List, Dict
335312
from fhir_pyrate.util.fhirobj import FHIRObj
@@ -354,14 +331,12 @@ df = search.bundles_to_dataframe(
354331
process_function=get_diagnostic_text,
355332
)
356333
```
357-
358-
1. Extract only part of the information using the `fhir_paths` argument. Here you can put a list
334+
3. Extract only part of the information using the `fhir_paths` argument. Here you can put a list
359335
of string that follow the [FHIRPath](https://hl7.org/fhirpath/) standard. For this purpose, we
360336
use the [fhirpath-py](https://github.com/beda-software/fhirpath-py) package, which uses the
361337
[antr4](https://github.com/antlr/antlr4) parser. Additionally, you can use tuples like `(key,
362338
fhir_path)`, where `key` will be the name of the column the information derived from that
363339
FHIRPath will be stored.
364-
365340
```python
366341
# Create bundles with Pirate
367342
search = ...
@@ -372,7 +347,6 @@ df = search.bundles_to_dataframe(
372347
fhir_paths=["id", ("code", "code.coding"), ("identifier", "identifier[0].code")],
373348
)
374349
```
375-
376350
**NOTE 1 on FHIR paths**: The standard also allows some primitive math operations such as modulus
377351
(`mod`) or integer division (`div`), and this may be problematic if there are fields of the
378352
resource that use these terms as attributes.
@@ -383,8 +357,7 @@ instead (as in 2.).
383357
**NOTE 2 on FHIR paths**: Since it is possible to specify the column name with a tuple
384358
`(key, fhir_path)`, it is important to know that if a key is used multiple times for different
385359
pieces of information but for the same resource, the field will be only filled with the first
386-
occurrence that is not None.
387-
360+
occurence that is not None.
388361
```python
389362
df = search.steal_bundles_to_dataframe(
390363
resource_type="DiagnosticReport",
@@ -412,7 +385,6 @@ df = search.steal_bundles_to_dataframe(
412385
```
413386

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

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

433405
Not all FHIR servers allow this (at least not the public ones that we have tried),
434406
but it is also possible to obtain multiple resources with just one query:
435-
436407
```python
437408
search = ...
438409
result_dfs = search.steal_bundles_to_dataframe(
@@ -460,7 +431,6 @@ result_dfs = search.steal_bundles_to_dataframe(
460431
num_pages=1,
461432
)
462433
```
463-
464434
In this case, a dictionary of DataFrames is returned, where the keys are the resource types.
465435
You can then select the single dictionary by doing `result_dfs["ImagingStudy"]`
466436
or `result_dfs["Patient"]`.
@@ -482,9 +452,14 @@ such that only the ones containing
482452
the actual resource name are kept if the resource name is specified in the path,
483453
and that a column full of `None`s is obtained in case no resource type is specified.
484454

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

487-
![FHIR-PYrate Logo](https://raw.githubusercontent.com/UMEssen/FHIR-PYrate/main/images/miner.svg)
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 />
488463

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

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

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

602577
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.
603578

604579
## License
605-
606580
This project is licenced under the [MIT Licence](LICENSE).
607581

608582
## Project status
609-
610583
The project is in active development.

0 commit comments

Comments
 (0)