Skip to content
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

Remove support for Python 3.8 #1236

Merged
merged 3 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ jobs:
windows-latest,
]
python: [
'3.8',
'3.9',
'3.10',
'3.11',
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ repos:
rev: v3.19.0
hooks:
- id: pyupgrade
args: ['--py38-plus', '--keep-runtime-typing']
args: ['--py39-plus', '--keep-runtime-typing']

- repo: https://github.com/PyCQA/doc8
rev: v1.1.2
Expand Down
3 changes: 1 addition & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import os
import sys
from datetime import date
from typing import List

sys.path.insert(0, os.path.abspath('../../src'))
import torchio # noqa: E402
Expand Down Expand Up @@ -83,7 +82,7 @@
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns: List[str] = []
exclude_patterns: list[str] = []

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'friendly'
Expand Down
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.12",
Expand All @@ -35,7 +34,7 @@ classifiers = [
"Typing :: Typed"
]
keywords = ["medical", "image processing", "pytorch", "augmentation", "mri"]
requires-python = ">=3.8,<3.13"
requires-python = ">=3.9,<3.13"
dependencies = [
"deprecated",
"humanize",
Expand Down
7 changes: 3 additions & 4 deletions src/torchio/data/dataset.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from __future__ import annotations

import copy
from collections.abc import Iterable
from collections.abc import Sequence
from typing import Callable
from typing import Iterable
from typing import List
from typing import Optional
from typing import Sequence

from torch.utils.data import Dataset

Expand Down Expand Up @@ -107,7 +106,7 @@ def from_batch(cls, batch: dict) -> SubjectsDataset:
batch: Dictionary generated by a data loader, containing data that
can be converted to instances of :class:`~.torchio.Subject`.
"""
subjects: List[Subject] = get_subjects_from_batch(batch)
subjects: list[Subject] = get_subjects_from_batch(batch)
return cls(subjects)

def dry_iter(self):
Expand Down
27 changes: 12 additions & 15 deletions src/torchio/data/image.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import warnings
from collections import Counter
from collections.abc import Sequence
from pathlib import Path
from typing import Any
from typing import Callable
from typing import Dict
from typing import List
from typing import Optional
from typing import Sequence
from typing import Tuple
from typing import Union

import humanize
Expand Down Expand Up @@ -51,8 +48,8 @@
from .io import write_image

PROTECTED_KEYS = DATA, AFFINE, TYPE, PATH, STEM
TypeBound = Tuple[float, float]
TypeBounds = Tuple[TypeBound, TypeBound, TypeBound]
TypeBound = tuple[float, float]
TypeBounds = tuple[TypeBound, TypeBound, TypeBound]

deprecation_message = (
'Setting the image data with the property setter is deprecated. Use the'
Expand Down Expand Up @@ -139,7 +136,7 @@ def __init__(
affine: Optional[TypeData] = None,
check_nans: bool = False, # removed by ITK by default
reader: Callable = read_image,
**kwargs: Dict[str, Any],
**kwargs: dict[str, Any],
):
self.check_nans = check_nans
self.reader = reader
Expand Down Expand Up @@ -336,7 +333,7 @@ def width(self) -> int:
return self.spatial_shape[0]

@property
def orientation(self) -> Tuple[str, str, str]:
def orientation(self) -> tuple[str, str, str]:
"""Orientation codes."""
return nib.aff2axcodes(self.affine)

Expand All @@ -349,14 +346,14 @@ def direction(self) -> TypeDirection3D:
return direction # type: ignore[return-value]

@property
def spacing(self) -> Tuple[float, float, float]:
def spacing(self) -> tuple[float, float, float]:
"""Voxel spacing in mm."""
_, spacing = get_rotation_and_spacing_from_affine(self.affine)
sx, sy, sz = spacing
return sx, sy, sz

@property
def origin(self) -> Tuple[float, float, float]:
def origin(self) -> tuple[float, float, float]:
"""Center of first voxel in array, in mm."""
ox, oy, oz = self.affine[:3, 3]
return ox, oy, oz
Expand Down Expand Up @@ -479,7 +476,7 @@ def _parse_single_path(
def _parse_path(
self,
path: Optional[Union[TypePath, Sequence[TypePath]]],
) -> Optional[Union[Path, List[Path]]]:
) -> Optional[Union[Path, list[Path]]]:
if path is None:
return None
elif isinstance(path, dict):
Expand Down Expand Up @@ -565,7 +562,7 @@ def load(self) -> None:
if self._loaded:
return

paths: List[Path]
paths: list[Path]
if self._is_multipath():
paths = self.path # type: ignore[assignment]
else:
Expand Down Expand Up @@ -807,12 +804,12 @@ def show(self, viewer_path: Optional[TypePath] = None) -> None:

def _crop_from_slices(
self,
slices: Union[TypeSlice, Tuple[TypeSlice, ...]],
slices: Union[TypeSlice, tuple[TypeSlice, ...]],
) -> 'Image':
from ..transforms import Crop

slices_tuple = to_tuple(slices) # type: ignore[assignment]
cropping: List[int] = []
cropping: list[int] = []
for dim, slice_ in enumerate(slices_tuple):
if isinstance(slice_, slice):
pass
Expand Down Expand Up @@ -914,7 +911,7 @@ def count_nonzero(self) -> int:
"""Get the number of voxels that are not 0."""
return int(self.data.count_nonzero().item())

def count_labels(self) -> Dict[int, int]:
def count_labels(self) -> dict[int, int]:
"""Get the number of voxels in each label."""
values_list = self.data.flatten().tolist()
counter = Counter(values_list)
Expand Down
3 changes: 1 addition & 2 deletions src/torchio/data/inference/aggregator.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import warnings
from typing import Optional
from typing import Tuple

import numpy as np
import torch
Expand Down Expand Up @@ -58,7 +57,7 @@ def _crop_patch(
patch: torch.Tensor,
location: np.ndarray,
overlap: np.ndarray,
) -> Tuple[torch.Tensor, np.ndarray]:
) -> tuple[torch.Tensor, np.ndarray]:
half_overlap = overlap // 2 # overlap is always even in grid sampler
index_ini, index_fin = location[:3], location[3:]

Expand Down
7 changes: 3 additions & 4 deletions src/torchio/data/io.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import warnings
from pathlib import Path
from typing import Optional
from typing import Tuple
from typing import Union

import nibabel as nib
Expand Down Expand Up @@ -283,7 +282,7 @@ def _write_niftyreg_matrix(matrix: TypeData, txt_path: TypePath) -> None:

def get_rotation_and_spacing_from_affine(
affine: np.ndarray,
) -> Tuple[np.ndarray, np.ndarray]:
) -> tuple[np.ndarray, np.ndarray]:
# From https://github.com/nipy/nibabel/blob/master/nibabel/orientations.py
rotation_zoom = affine[:3, :3]
spacing = np.sqrt(np.sum(rotation_zoom * rotation_zoom, axis=0))
Expand Down Expand Up @@ -337,7 +336,7 @@ def nib_to_sitk(
def sitk_to_nib(
image: sitk.Image,
keepdim: bool = False,
) -> Tuple[np.ndarray, np.ndarray]:
) -> tuple[np.ndarray, np.ndarray]:
data = sitk.GetArrayFromImage(image).transpose()
data = check_uint_to_int(data)
num_components = image.GetNumberOfComponentsPerPixel()
Expand Down Expand Up @@ -391,7 +390,7 @@ def get_sitk_metadata_from_ras_affine(
affine: np.ndarray,
is_2d: bool = False,
lps: bool = True,
) -> Tuple[TypeTripletFloat, TypeTripletFloat, TypeDirection]:
) -> tuple[TypeTripletFloat, TypeTripletFloat, TypeDirection]:
direction_ras, spacing_array = get_rotation_and_spacing_from_affine(affine)
origin_ras = affine[:3, 3]
origin_lps = np.dot(FLIPXY_33, origin_ras)
Expand Down
6 changes: 2 additions & 4 deletions src/torchio/data/loader.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from typing import Any
from typing import Callable
from typing import Dict
from typing import List
from typing import Optional
from typing import TypeVar

Expand All @@ -19,7 +17,7 @@ class SubjectsLoader(DataLoader):
def __init__(
self,
dataset: Dataset,
collate_fn: Optional[Callable[[List[T]], Any]] = None,
collate_fn: Optional[Callable[[list[T]], Any]] = None,
**kwargs,
):
if collate_fn is None:
Expand All @@ -31,7 +29,7 @@ def __init__(
)

@staticmethod
def _collate(subjects: List[Subject]) -> Dict[str, Any]:
def _collate(subjects: list[Subject]) -> dict[str, Any]:
first_subject = subjects[0]
batch_dict = {}
for key in first_subject.keys():
Expand Down
5 changes: 2 additions & 3 deletions src/torchio/data/queue.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from collections.abc import Iterator
from itertools import islice
from typing import Iterator
from typing import List
from typing import Optional

import humanize
Expand Down Expand Up @@ -210,7 +209,7 @@ def __init__(
self._num_sampled_subjects = 0
if start_background:
self._initialize_subjects_iterable()
self.patches_list: List[Subject] = []
self.patches_list: list[Subject] = []

if self.shuffle_subjects and self.subject_sampler is not None:
raise ValueError(
Expand Down
2 changes: 1 addition & 1 deletion src/torchio/data/sampler/grid.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Generator
from collections.abc import Generator
from typing import Optional
from typing import Union

Expand Down
5 changes: 2 additions & 3 deletions src/torchio/data/sampler/label.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from typing import Dict
from typing import Optional

import numpy as np
Expand Down Expand Up @@ -63,7 +62,7 @@ def __init__(
self,
patch_size: TypeSpatialShape,
label_name: Optional[str] = None,
label_probabilities: Optional[Dict[int, float]] = None,
label_probabilities: Optional[dict[int, float]] = None,
):
super().__init__(patch_size, probability_map=label_name)
self.label_probabilities_dict = label_probabilities
Expand Down Expand Up @@ -106,7 +105,7 @@ def get_probability_map(self, subject: Subject) -> torch.Tensor:
@staticmethod
def get_probabilities_from_label_map(
label_map: torch.Tensor,
label_probabilities_dict: Dict[int, float],
label_probabilities_dict: dict[int, float],
patch_size: np.ndarray,
) -> torch.Tensor:
"""Create probability map according to label map probabilities."""
Expand Down
2 changes: 1 addition & 1 deletion src/torchio/data/sampler/sampler.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Generator
from collections.abc import Generator
from typing import Optional

import numpy as np
Expand Down
2 changes: 1 addition & 1 deletion src/torchio/data/sampler/uniform.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Generator
from collections.abc import Generator
from typing import Optional

import torch
Expand Down
2 changes: 1 addition & 1 deletion src/torchio/data/sampler/weighted.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Generator
from collections.abc import Generator
from typing import Optional

import numpy as np
Expand Down
Loading
Loading