Skip to content

Commit fd3d124

Browse files
authored
Merge pull request #138 from JannisStraus/137-dicom-anonymization-missing
137 fix mypy typing and bump up versions
2 parents 6a19dc5 + 8662252 commit fd3d124

18 files changed

Lines changed: 1124 additions & 1101 deletions

.flake8

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

.github/workflows/python-publish.yml

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,19 @@ permissions:
1111

1212
jobs:
1313
deploy:
14-
1514
runs-on: ubuntu-latest
1615

1716
steps:
18-
- uses: actions/checkout@v3
19-
- name: Set up Python 3.8
20-
uses: actions/setup-python@v3
21-
with:
22-
python-version: "3.8"
23-
- name: Install poetry
24-
run: |
25-
curl -sSL https://install.python-poetry.org | python3 -
26-
export PATH="/root/.local/bin:$PATH"
27-
poetry run pip install -U pip
28-
poetry install
29-
- name: Publish package
30-
run: poetry publish --build --username __token__ --password ${{ secrets.PYPI_TOKEN }}
17+
- uses: actions/checkout@v3
18+
- name: Set up Python 3.8
19+
uses: actions/setup-python@v3
20+
with:
21+
python-version: "3.8"
22+
- name: Install poetry
23+
run: |
24+
curl -sSL https://install.python-poetry.org | python3 -
25+
export PATH="/root/.local/bin:$PATH"
26+
poetry run pip install -U pip
27+
poetry install
28+
- name: Publish package
29+
run: poetry publish --build --username __token__ --password ${{ secrets.PYPI_TOKEN }}

.mypy.ini

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

.pre-commit-config.yaml

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,38 @@
1+
# See https://gitlab.uk-essen.de/ship-ai/pre-commit-hooks for the newest version
2+
13
repos:
2-
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v4.0.1
4-
hooks:
5-
- id: end-of-file-fixer
6-
- id: trailing-whitespace
7-
- repo: https://github.com/psf/black
8-
rev: 22.3.0
9-
hooks:
10-
- id: black
11-
- repo: https://github.com/pycqa/isort
12-
rev: 5.12.0
13-
hooks:
14-
- id: isort
15-
exclude: _external
16-
- repo: https://github.com/PyCQA/flake8
17-
rev: 3.9.2
18-
hooks:
19-
- id: flake8
20-
exclude: _external
21-
additional_dependencies: ["flake8-bugbear==21.4.3"]
22-
- repo: https://github.com/pre-commit/mirrors-mypy
23-
rev: v0.910
24-
hooks:
25-
- id: mypy
26-
exclude: _external
27-
args: ["--install-types", "--non-interactive"]
4+
- repo: https://github.com/charliermarsh/ruff-pre-commit
5+
rev: v0.11.6
6+
hooks:
7+
- id: ruff
8+
args: [--fix]
9+
exclude: examples
10+
- id: ruff-format
11+
exclude: examples
12+
13+
- repo: https://github.com/pre-commit/mirrors-mypy
14+
rev: v1.15.0
15+
hooks:
16+
- id: mypy
17+
language_version: python3.10
18+
additional_dependencies: [types-python-dateutil, types-requests]
19+
20+
- repo: https://github.com/pre-commit/mirrors-prettier
21+
rev: v4.0.0-alpha.8
22+
hooks:
23+
- id: prettier
24+
types_or: [html, css, json, javascript, xml, yaml]
25+
exclude: node_modules
26+
27+
- repo: https://github.com/tox-dev/pyproject-fmt
28+
rev: v2.5.1
29+
hooks:
30+
- id: pyproject-fmt
31+
types: [toml]
32+
33+
- repo: https://github.com/pre-commit/pre-commit-hooks
34+
rev: v5.0.0
35+
hooks:
36+
- id: end-of-file-fixer
37+
- id: check-merge-conflict
38+
- id: check-added-large-files

fhir_pyrate/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
__all__ = [
2626
"Ahoy",
27+
"DicomDownloader",
2728
"Miner",
2829
"Pirate",
29-
"DicomDownloader",
3030
]

fhir_pyrate/ahoy.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@ class Ahoy:
4040

4141
def __init__(
4242
self,
43-
auth_url: str = None,
43+
auth_url: Optional[str] = None,
4444
auth_type: Optional[str] = "token",
45-
refresh_url: str = None,
46-
username: str = None,
45+
refresh_url: Optional[str] = None,
46+
username: Optional[str] = None,
4747
auth_method: Optional[str] = "password",
48-
token: str = None,
48+
token: Optional[str] = None,
4949
max_login_attempts: int = 5,
50-
token_refresh_delta: Union[int, timedelta] = None,
51-
session: requests.Session = None,
50+
token_refresh_delta: Optional[Union[int, timedelta]] = None,
51+
session: Optional[requests.Session] = None,
5252
) -> None:
5353
self.auth_type = auth_type
5454
self.auth_method = auth_method
@@ -82,7 +82,7 @@ def __exit__(
8282
self.close()
8383

8484
def change_environment_variable_name(
85-
self, user_env: str = None, pass_env: str = None
85+
self, user_env: Optional[str] = None, pass_env: Optional[str] = None
8686
) -> None:
8787
"""
8888
Change the name of the variables used to retrieve username and password.

fhir_pyrate/dicom_downloader.py

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,18 @@
1414
from contextlib import contextmanager
1515
from functools import partial
1616
from types import TracebackType
17-
from typing import Dict, Generator, List, Optional, TextIO, Tuple, Type, Union
17+
from typing import (
18+
ClassVar,
19+
Dict,
20+
FrozenSet,
21+
Generator,
22+
List,
23+
Optional,
24+
TextIO,
25+
Tuple,
26+
Type,
27+
Union,
28+
)
1829

1930
import pandas as pd
2031
import pydicom
@@ -67,7 +78,7 @@ def fileno(file_or_fd: TextIO) -> Optional[int]:
6778
@contextmanager
6879
def stdout_redirected(
6980
to: Union[str, TextIO] = os.devnull, stdout: Optional[TextIO] = None
70-
) -> Generator:
81+
) -> Generator[Optional[TextIO], None, None]:
7182
if platform.system() == "Windows":
7283
yield None
7384
return
@@ -136,23 +147,25 @@ class DicomDownloader:
136147
:param num_processes: The number of processes to run for downloading
137148
"""
138149

139-
ACCEPTED_FORMATS = {
140-
".dcm",
141-
".nia",
142-
".nii",
143-
".nii.gz",
144-
".hdr",
145-
".img",
146-
".img.gz",
147-
".tif",
148-
".TIF",
149-
".tiff",
150-
".TIFF",
151-
".mha",
152-
".mhd",
153-
".nrrd",
154-
".nhdr",
155-
}
150+
ACCEPTED_FORMATS: ClassVar[FrozenSet[str]] = frozenset(
151+
{
152+
".dcm",
153+
".nia",
154+
".nii",
155+
".nii.gz",
156+
".hdr",
157+
".img",
158+
".img.gz",
159+
".tif",
160+
".TIF",
161+
".tiff",
162+
".TIFF",
163+
".mha",
164+
".mhd",
165+
".nrrd",
166+
".nhdr",
167+
}
168+
)
156169

157170
def __init__(
158171
self,
@@ -239,7 +252,7 @@ def __exit__(
239252
@staticmethod
240253
def get_download_id(
241254
study_uid: str,
242-
series_uid: str = None,
255+
series_uid: Optional[str] = None,
243256
always_download_in_study_folder: bool = False,
244257
) -> str:
245258
"""
@@ -259,7 +272,7 @@ def get_download_id(
259272

260273
def get_download_path(self, download_id: str) -> pathlib.Path:
261274
"""
262-
Builds the folder hierarchy where the data will be stored. The hierarchy depends on the
275+
Build the folder hierarchy where the data will be stored. The hierarchy depends on the
263276
`hierarchical_storage` parameter. Given a download ID
264277
263a1dad02916f5eca3c4eec51dc9d281735b47b8eb8bc2343c56e6ccd and `hierarchical_storage` = 2,
265278
the data will be stored in 26/3a/1dad02916f5eca3c4eec51dc9d281735b47b8eb8bc2343c56e6ccd.
@@ -277,13 +290,13 @@ def get_download_path(self, download_id: str) -> pathlib.Path:
277290
def download_data(
278291
self,
279292
study_uid: str,
280-
series_uid: str = None,
293+
series_uid: Optional[str] = None,
281294
output_dir: Union[str, pathlib.Path] = "out",
282295
save_metadata: bool = True,
283296
existing_ids: Optional[List[str]] = None,
284297
) -> Tuple[List[Dict[str, str]], List[Dict[str, str]]]:
285298
"""
286-
Downloads the data related to the StudyInstanceUID and SeriesInstanceUID (if given,
299+
Download the data related to the StudyInstanceUID and SeriesInstanceUID (if given,
287300
otherwise the entire study will be downloaded).
288301
289302
:param study_uid: The StudyInstanceUID
@@ -333,7 +346,7 @@ def download_data(
333346
base_dict[self.series_instance_uid_field] = series_uid
334347

335348
# Init the readers/writers
336-
series_reader = sitk.ImageSeriesReader() # type: ignore
349+
series_reader = sitk.ImageSeriesReader()
337350
with tempfile.TemporaryDirectory() as tmp_dir:
338351
# Create the download dir
339352
current_tmp_dir = pathlib.Path(tmp_dir)
@@ -361,11 +374,11 @@ def download_data(
361374
progress_bar.close()
362375

363376
# Get Series ID names from folder
364-
series_uids = sitk.ImageSeriesReader.GetGDCMSeriesIDs(str(current_tmp_dir)) # type: ignore
377+
series_uids = sitk.ImageSeriesReader.GetGDCMSeriesIDs(str(current_tmp_dir))
365378
logger.info(f"Study ID has {len(series_uids)} series.")
366379
for series in series_uids:
367380
# Get the DICOMs corresponding to the series
368-
files = series_reader.GetGDCMSeriesFileNames( # type: ignore
381+
files = series_reader.GetGDCMSeriesFileNames(
369382
str(current_tmp_dir), series
370383
)
371384
current_dict = base_dict.copy()
@@ -374,11 +387,12 @@ def download_data(
374387
)
375388
try:
376389
# Read the series
377-
with simpleitk_warning_file.open("w") as f, stdout_redirected(
378-
f, stdout=sys.stderr
390+
with (
391+
simpleitk_warning_file.open("w") as f,
392+
stdout_redirected(f, stdout=sys.stderr),
379393
):
380-
series_reader.SetFileNames(files) # type: ignore
381-
image = series_reader.Execute() # type: ignore
394+
series_reader.SetFileNames(files)
395+
image = series_reader.Execute()
382396
with simpleitk_warning_file.open("r") as f:
383397
content = f.read()
384398
if "warning" in content.lower():
@@ -431,9 +445,9 @@ def download_data(
431445
series_download_dir / f"{series}_meta.dcm",
432446
)
433447
dcm_info = pydicom.dcmread(str(files[0]), stop_before_pixels=True)
434-
current_dict[
435-
self.deid_study_instance_uid_field
436-
] = dcm_info.StudyInstanceUID
448+
current_dict[self.deid_study_instance_uid_field] = (
449+
dcm_info.StudyInstanceUID
450+
)
437451
current_dict[self.deid_series_instance_uid_field] = series
438452
downloaded_series_info.append(current_dict)
439453

@@ -442,7 +456,7 @@ def download_data(
442456
def fix_mapping_dataframe(
443457
self,
444458
df: pd.DataFrame,
445-
mapping_df: pd.DataFrame = None,
459+
mapping_df: Optional[pd.DataFrame] = None,
446460
output_dir: Union[str, pathlib.Path] = "out",
447461
study_uid_col: str = "study_instance_uid",
448462
series_uid_col: str = "series_instance_uid",
@@ -464,7 +478,8 @@ def fix_mapping_dataframe(
464478
output_dir = pathlib.Path(output_dir)
465479
if not output_dir.exists() or not len(list(output_dir.glob("*"))):
466480
warnings.warn(
467-
"Cannot fix the mapping file if the output directory does not exist."
481+
"Cannot fix the mapping file if the output directory does not exist.",
482+
stacklevel=2,
468483
)
469484
return None
470485
if mapping_df is None:
@@ -547,7 +562,7 @@ def download_data_from_dataframe(
547562
output_dir: Union[str, pathlib.Path] = "out",
548563
study_uid_col: str = "study_instance_uid",
549564
series_uid_col: Optional[str] = "series_instance_uid",
550-
mapping_df: pd.DataFrame = None,
565+
mapping_df: Optional[pd.DataFrame] = None,
551566
download_full_study: bool = False,
552567
save_metadata: bool = True,
553568
) -> Tuple[pd.DataFrame, pd.DataFrame]:
@@ -593,7 +608,8 @@ def download_data_from_dataframe(
593608
warnings.warn(
594609
"download_full_study = False will only download a specified series but "
595610
"have not provided a valid Series UID column of the DataFrame, "
596-
"as a result the full study will be downloaded."
611+
"as a result the full study will be downloaded.",
612+
stacklevel=2,
597613
)
598614

599615
# Create list of rows

0 commit comments

Comments
 (0)