From 0983eb113746a9961f52bb2393a82c6d3416d9e6 Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Wed, 16 Oct 2024 09:53:26 +0200 Subject: [PATCH] lint: ruff --- .github/workflows/test.yml | 2 +- examples/example_anat_EPI.py | 3 ++- examples/example_generate_phantom.py | 10 +++++----- examples/example_gpu_anat_spirals.py | 1 - src/snake/__init__.py | 2 +- src/snake/core/engine/base.py | 2 -- src/snake/core/engine/nufft.py | 1 - src/snake/core/handlers/motion/__init__.py | 3 ++- src/snake/core/handlers/noise.py | 14 ++++++++------ src/snake/core/phantom/static.py | 2 +- src/snake/core/sampling/factories.py | 2 +- src/snake/core/sampling/samplers.py | 2 -- src/snake/core/simulation.py | 3 ++- src/snake/toolkit/analysis/metrics.py | 6 ++++-- src/snake/toolkit/analysis/stats.py | 1 - src/snake/toolkit/cli/acquisition.py | 1 - src/snake/toolkit/cli/config.py | 10 ++-------- src/snake/toolkit/cli/reconstruction.py | 2 +- src/snake/toolkit/plotting.py | 18 ++++++++++++------ src/snake/toolkit/reconstructors/__init__.py | 3 ++- src/snake/toolkit/reconstructors/fourier.py | 20 +++++++++++++++++--- 21 files changed, 61 insertions(+), 47 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9bfc81a..dbd5006 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,7 @@ jobs: - name: Linter run: | black --check src tests - ruff . + ruff check . - name: Annotate locations with typos uses: codespell-project/codespell-problem-matcher@v1 - name: Codespell diff --git a/examples/example_anat_EPI.py b/examples/example_anat_EPI.py index b1b07b9..f02c13c 100644 --- a/examples/example_anat_EPI.py +++ b/examples/example_anat_EPI.py @@ -41,7 +41,8 @@ # # The simulation acquires # the data describe in a phantom. A phantom consists of fuzzy segmentation of -# head tissue, and their MR intrisic parameters (density, T1, T2, T2*, magnetic susceptibilities) +# head tissue, and their MR intrisic parameters +# (density, T1, T2, T2*, magnetic susceptibilities) # # Here we use Brainweb reference mask and values for convenience. diff --git a/examples/example_generate_phantom.py b/examples/example_generate_phantom.py index a296d61..fc7f3dc 100644 --- a/examples/example_generate_phantom.py +++ b/examples/example_generate_phantom.py @@ -5,17 +5,17 @@ Example for generating a phantom and visualizing the contrast at different TE values. """ -import numpy as np from snake.core.phantom import Phantom from snake.core.engine.utils import get_ideal_phantom from snake.core.simulation import SimConfig, GreConfig -# + -# This notebook has interactive widgets, run it in google colab or locally to enjoy it fully -# - - +# %% +# This notebook has interactive widgets, run it in google colab or locally to +# enjoy it fully +# +# %% shape = (181, 217, 181) TR = 100 TE = 25 diff --git a/examples/example_gpu_anat_spirals.py b/examples/example_gpu_anat_spirals.py index f6e06bb..a727ab5 100644 --- a/examples/example_gpu_anat_spirals.py +++ b/examples/example_gpu_anat_spirals.py @@ -13,7 +13,6 @@ # %% # Imports -import numpy as np from snake.core.simulation import SimConfig, default_hardware, GreConfig from snake.core.phantom import Phantom from snake.core.smaps import get_smaps diff --git a/src/snake/__init__.py b/src/snake/__init__.py index c291421..c66ac16 100644 --- a/src/snake/__init__.py +++ b/src/snake/__init__.py @@ -1 +1 @@ -"""SNAKE Package""" +"""SNAKE Package.""" diff --git a/src/snake/core/engine/base.py b/src/snake/core/engine/base.py index fa625cb..6b1467b 100644 --- a/src/snake/core/engine/base.py +++ b/src/snake/core/engine/base.py @@ -9,7 +9,6 @@ from collections.abc import Mapping, Sequence from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor, as_completed from multiprocessing.managers import SharedMemoryManager -from pathlib import Path from tempfile import TemporaryDirectory from typing import Any, ClassVar @@ -164,7 +163,6 @@ def __call__( **kwargs: Any, ): """Perform the acquisition and fill the dataset.""" - # Create the base dataset make_base_mrd(filename, sampler, phantom, sim_conf, handlers, smaps, coil_cov) diff --git a/src/snake/core/engine/nufft.py b/src/snake/core/engine/nufft.py index 3a42969..67dabd3 100644 --- a/src/snake/core/engine/nufft.py +++ b/src/snake/core/engine/nufft.py @@ -1,7 +1,6 @@ """Acquisition engine using nufft.""" from collections.abc import Sequence -from copy import deepcopy import ismrmrd as mrd import numpy as np diff --git a/src/snake/core/handlers/motion/__init__.py b/src/snake/core/handlers/motion/__init__.py index 1839975..d40340a 100644 --- a/src/snake/core/handlers/motion/__init__.py +++ b/src/snake/core/handlers/motion/__init__.py @@ -1,4 +1,5 @@ -#!/usr/bin/env python3 +"""Motion Handler Module.""" + from .image import RandomMotionImageHandler __all__ = ["RandomMotionImageHandler"] diff --git a/src/snake/core/handlers/noise.py b/src/snake/core/handlers/noise.py index 9ab67aa..04fe06e 100644 --- a/src/snake/core/handlers/noise.py +++ b/src/snake/core/handlers/noise.py @@ -1,17 +1,18 @@ +"""Handler that add noise to the phantom in the image domain.""" + import numpy as np +from numpy.typing import NDArray from copy import deepcopy -from numpy.typing import NDArray -import pandas as pd from functools import partial -from ..._meta import LogMixin from ..phantom import Phantom, DynamicData from ..simulation import SimConfig from .base import AbstractHandler -def apply_noise(phantom: Phantom, data, idx, variance) -> Phantom: +def apply_noise(phantom: Phantom, data: NDArray, idx: int, variance: float) -> Phantom: + """Apply noise to the phantom at time idx.""" rng = np.random.default_rng((int(data[0, idx]), idx)) # new seed for every frame noise_tissue = rng.standard_normal(size=phantom.masks.shape[1:]) * np.sqrt(variance) new_phantom = deepcopy(phantom) @@ -21,12 +22,13 @@ def apply_noise(phantom: Phantom, data, idx, variance) -> Phantom: class NoiseHandler(AbstractHandler): + """Handler that add noise tot the phantom in the image domain.""" __handler_name__ = "noise-image" variance: float def get_static(self, phantom: Phantom, sim_conf: SimConfig) -> Phantom: - """Add a static noise tissue""" + """Add a static noise tissue.""" noise_tissue = np.ones_like(phantom.masks[0]) noise_props = np.array([[100000, 100000, 100000, 1, 0]]) new_phantom = phantom.add_tissue( @@ -36,7 +38,7 @@ def get_static(self, phantom: Phantom, sim_conf: SimConfig) -> Phantom: return new_phantom def get_dynamic(self, phantom: Phantom, sim_conf: SimConfig) -> DynamicData: - """Add a dynamic noise tissue""" + """Add a dynamic noise tissue.""" return DynamicData( "noise", data=np.ones((1, sim_conf.max_n_shots), dtype=np.int32) * sim_conf.rng_seed, diff --git a/src/snake/core/phantom/static.py b/src/snake/core/phantom/static.py index ed2dcb2..2336605 100644 --- a/src/snake/core/phantom/static.py +++ b/src/snake/core/phantom/static.py @@ -56,7 +56,7 @@ def add_tissue( tissue_name: str, mask: NDArray[np.float32], props: NDArray[np.float32], - phantom_name=None, + phantom_name: str | None = None, ) -> Phantom: """Add a tissue to the phantom. Creates a new Phantom object.""" masks = np.concatenate((self.masks, mask[None, ...]), axis=0) diff --git a/src/snake/core/sampling/factories.py b/src/snake/core/sampling/factories.py index e37dc93..18fcdbb 100644 --- a/src/snake/core/sampling/factories.py +++ b/src/snake/core/sampling/factories.py @@ -104,7 +104,7 @@ def get_kspace_slice_loc( ) rng = validate_rng(rng) - def _get_samples(p): + def _get_samples(p: NDArray) -> list[int]: p /= np.sum(p) return list(rng.choice(borders, size=n_samples_borders, replace=False, p=p)) diff --git a/src/snake/core/sampling/samplers.py b/src/snake/core/sampling/samplers.py index 312f7b9..aa8def2 100644 --- a/src/snake/core/sampling/samplers.py +++ b/src/snake/core/sampling/samplers.py @@ -185,7 +185,6 @@ class LoadTrajectorySampler(NonCartesianAcquisitionSampler): def _single_frame(self, sim_conf: SimConfig) -> NDArray: """Load the trajectory.""" - data = read_trajectory(self.path, raster_time=self.raster_time)[0] data /= 0.5 * data.max() return data @@ -262,7 +261,6 @@ class EPI3dAcquisitionSampler(BaseSampler): def _single_frame(self, sim_conf: SimConfig) -> NDArray: """Generate the sampling pattern.""" - return stacked_epi_factory( shape=sim_conf.shape, accelz=self.accelz, diff --git a/src/snake/core/simulation.py b/src/snake/core/simulation.py index 8f997cc..cbef82c 100644 --- a/src/snake/core/simulation.py +++ b/src/snake/core/simulation.py @@ -48,7 +48,8 @@ def _repr_html_(obj: Any, vertical: bool = True) -> str: field_value_str = repr(field_value) table_rows.append( - f"{field_name} ({field_type}){field_value_str}" + f"{field_name}({field_type})" + f"{field_value_str}" ) else: table_rows.append( diff --git a/src/snake/toolkit/analysis/metrics.py b/src/snake/toolkit/analysis/metrics.py index 6013735..4d7731b 100644 --- a/src/snake/toolkit/analysis/metrics.py +++ b/src/snake/toolkit/analysis/metrics.py @@ -54,8 +54,10 @@ def get_snr(test: NDArray, ref: NDArray, roi: NDArray | None = None) -> float: return np.sqrt(np.mean(abs(signal) ** 2) / np.mean(abs(noise) ** 2)) -def get_snr_console_db(test: NDArray, roi_data=None, roi_noise=None) -> float: - """Compute the SNR 'like at the console' +def get_snr_console_db( + test: NDArray, roi_data: NDArray = None, roi_noise: NDArray = None +) -> float: + """Compute the SNR 'like at the console'. using region of interest for the signal and noise in the same image. diff --git a/src/snake/toolkit/analysis/stats.py b/src/snake/toolkit/analysis/stats.py index 2d91b98..a49930b 100644 --- a/src/snake/toolkit/analysis/stats.py +++ b/src/snake/toolkit/analysis/stats.py @@ -7,7 +7,6 @@ import numpy as np from nilearn.glm.first_level import make_first_level_design_matrix, run_glm -from nilearn.glm.first_level.hemodynamic_models import _resample_regressor from nilearn.glm import compute_contrast, expression_to_contrast_vector from nilearn.glm.thresholding import fdr_threshold from scipy.stats import norm diff --git a/src/snake/toolkit/cli/acquisition.py b/src/snake/toolkit/cli/acquisition.py index 096f397..f73c142 100644 --- a/src/snake/toolkit/cli/acquisition.py +++ b/src/snake/toolkit/cli/acquisition.py @@ -5,7 +5,6 @@ from omegaconf import OmegaConf from snake.core.engine import BaseAcquisitionEngine from snake.core.handlers import HandlerList -from snake.mrd_utils import make_base_mrd from snake.core.phantom import Phantom from snake.core.smaps import get_smaps from snake.toolkit.cli.config import ConfigSNAKE, cleanup_cuda, make_hydra_cli diff --git a/src/snake/toolkit/cli/config.py b/src/snake/toolkit/cli/config.py index 34de7d7..791257a 100644 --- a/src/snake/toolkit/cli/config.py +++ b/src/snake/toolkit/cli/config.py @@ -5,7 +5,6 @@ from dataclasses import dataclass, field import hydra from hydra.core.config_store import ConfigStore -from hydra import compose, initialize from omegaconf import OmegaConf, DictConfig from snake.core.simulation import SimConfig @@ -122,13 +121,8 @@ def cleanup_cuda() -> None: cp._default_pinned_memory_pool = cp.cuda.PinnedMemoryPool() -def make_hydra_cli(fun): +def make_hydra_cli(fun: callable) -> callable: + """Create a Hydra CLI for the function.""" return hydra.main( version_base=None, config_path="../../../cli-conf", config_name="config" )(fun) - - -def load_config(filename, *overrides): - with initialize(config_path="../../../cli-conf", job_name="test_app"): - cfg = compose(config_name="config", overrides=list(overrides)) - return cfg diff --git a/src/snake/toolkit/cli/reconstruction.py b/src/snake/toolkit/cli/reconstruction.py index d3eff6f..ab456d8 100644 --- a/src/snake/toolkit/cli/reconstruction.py +++ b/src/snake/toolkit/cli/reconstruction.py @@ -81,7 +81,7 @@ def reconstruction(cfg: DictConfig) -> None: gc.collect() results = [] - for name, rec in cfg.reconstructors.items(): + for _name, rec in cfg.reconstructors.items(): rec_str = str(rec) # FIXME Also use parameters of reconstructors data_rec_file = Path(f"data_rec_{rec_str}.npy").resolve() data_zscore_file = Path(f"data_zscore_{rec_str}.npy").resolve() diff --git a/src/snake/toolkit/plotting.py b/src/snake/toolkit/plotting.py index b6e3be8..bb2ef57 100644 --- a/src/snake/toolkit/plotting.py +++ b/src/snake/toolkit/plotting.py @@ -55,15 +55,21 @@ def get_axis_properties( cmin = max(0, cmin - arr_pad) cmax = min(cmax + arr_pad, mask.shape[1]) bbox[i] = (slice(rmin, rmax), slice(cmin, cmax)) - hdiv, vdiv = get_hdiv_vdiv(array_bg, bbox, slices, width_inches, cbar=cbar) + hdiv, vdiv = _get_hdiv_vdiv(array_bg, bbox, slices, width_inches, cbar=cbar) return hdiv, vdiv, tuple(bbox), slices -def get_hdiv_vdiv(array_bg, bbox, slices, width_inches, cbar=False): +def _get_hdiv_vdiv( + array_bg: NDArray, + bbox: tuple[tuple[slice]], + slices: tuple[slice], + width_inches: float, + cbar: bool = False, +) -> tuple[NDArray, NDArray]: sizes = np.array([(bb.stop - bb.start) for b in bbox for bb in b]) - sizes = tuple(array_bg[s][b].shape for s, b in zip(slices, bbox)) + sizes = tuple(array_bg[s][b].shape for s, b in zip(slices, bbox, strict=False)) alpha1 = sizes[1][1] / sizes[2][1] update_sizes = [[0, 0], [0, 0], [0, 0]] update_sizes[2][0] = sizes[2][0] @@ -90,7 +96,7 @@ def get_hdiv_vdiv(array_bg, bbox, slices, width_inches, cbar=False): 0.02 * hdiv[0], ] ) - hdivv = np.array(hdiv) + np.array(hdiv) height_inches = width_inches * aspect vdiv = np.array([height_inches * split_tb, height_inches * (1 - split_tb)]) return hdiv, vdiv @@ -113,7 +119,7 @@ def plot_frames_activ( bbox: tuple[Any, ...], z_thresh: float = 3, z_max: float = 11, - bg_cmap="gray", + bg_cmap: str = "gray", ) -> tuple[plt.Axes, matplotlib.image.AxesImage]: """Plot activation maps and background. @@ -189,7 +195,7 @@ def axis3dcut( background, cuts_, width_inches, cbar=cbar ) elif bbox is not None and slices is not None: - hdiv, vdiv = get_hdiv_vdiv(background, bbox, slices, width_inches, cbar=cbar) + hdiv, vdiv = _get_hdiv_vdiv(background, bbox, slices, width_inches, cbar=cbar) bbox_ = bbox slices_ = slices else: diff --git a/src/snake/toolkit/reconstructors/__init__.py b/src/snake/toolkit/reconstructors/__init__.py index 74cac02..fdc60f4 100644 --- a/src/snake/toolkit/reconstructors/__init__.py +++ b/src/snake/toolkit/reconstructors/__init__.py @@ -1,4 +1,5 @@ -#!/usr/bin/env python3 +"""Reconstructors wrapping different reconstruction algorithms.""" + from .base import BaseReconstructor from .pysap import ZeroFilledReconstructor, SequentialReconstructor diff --git a/src/snake/toolkit/reconstructors/fourier.py b/src/snake/toolkit/reconstructors/fourier.py index 2b86340..d510dbc 100644 --- a/src/snake/toolkit/reconstructors/fourier.py +++ b/src/snake/toolkit/reconstructors/fourier.py @@ -1,9 +1,10 @@ """FFT operators for MRI reconstruction.""" +from numpy.typing import NDArray import scipy as sp -def fft(image, axis=-1): +def fft(image: NDArray, axis: int | tuple[int] = -1) -> NDArray: """Apply the FFT operator. Parameters @@ -24,8 +25,21 @@ def fft(image, axis=-1): ) -def ifft(kspace_data, axis=-1): - """Apply the inverse FFT operator.""" +def ifft(kspace_data: NDArray, axis: int | tuple[int] = -1) -> NDArray: + """Apply the inverse FFT operator. + + Parameters + ---------- + kspace_data : array + Image in space. + axis : int + Axis to apply the FFT. + + Returns + ------- + image_data : array + image data. + """ return sp.fft.fftshift( sp.fft.ifftn(sp.fft.ifftshift(kspace_data, axes=axis), norm="ortho", axes=axis), axes=axis,