diff --git a/src/depiction/evaluate_signal_proc.py b/src/depiction/evaluate_signal_proc.py index 474c491..2e414d3 100644 --- a/src/depiction/evaluate_signal_proc.py +++ b/src/depiction/evaluate_signal_proc.py @@ -26,7 +26,8 @@ def evaluate(self, mz_values: np.ndarray, int_values: np.ndarray) -> np.ndarray: # Don't filter return int_values else: - # the problem with below's implementation was, that e.g. for input of size 1 it would create an output of size 5 (since it choses the bigger size of the two arrays) + # the problem with below's implementation was, that e.g. for input of size 1 + # it would create an output of size 5 (since it choses the bigger size of the two arrays) # return scipy.signal.convolve(int_array, gaussian_filter, mode='same') values = np.convolve(int_values, gaussian_filter, mode="same") values[0] = int_values[0] diff --git a/src/depiction/persistence/imzml_mode_enum.py b/src/depiction/persistence/imzml_mode_enum.py index ee6f5f0..fdb8a76 100644 --- a/src/depiction/persistence/imzml_mode_enum.py +++ b/src/depiction/persistence/imzml_mode_enum.py @@ -1,3 +1,4 @@ +from __future__ import annotations import enum @@ -8,12 +9,12 @@ class ImzmlModeEnum(enum.Enum): PROCESSED = enum.auto() @classmethod - def as_pyimzml_str(cls, instance) -> str: + def as_pyimzml_str(cls, instance: ImzmlModeEnum) -> str: """Returns the string representation of the enum value as used by pyimzml.""" return instance.name.lower() @classmethod - def from_pyimzml_str(cls, value: str) -> "ImzmlModeEnum": + def from_pyimzml_str(cls, value: str) -> ImzmlModeEnum: if value == "continuous": return cls.CONTINUOUS elif value == "processed": diff --git a/src/depiction/persistence/imzml_read_file.py b/src/depiction/persistence/imzml_read_file.py index ec48513..42eb4b4 100644 --- a/src/depiction/persistence/imzml_read_file.py +++ b/src/depiction/persistence/imzml_read_file.py @@ -3,7 +3,7 @@ from contextlib import contextmanager from functools import cached_property from pathlib import Path -from typing import Any, Optional +from typing import Any, Optional, TextIO import pyimzml.ImzMLParser from numpy.typing import NDArray @@ -164,7 +164,7 @@ def summary(self, checksums: bool = True) -> str: f"{mz_range_line}" ) - def print_summary(self, checksums: bool = True, file=None) -> None: + def print_summary(self, checksums: bool = True, file: TextIO | None = None) -> None: print(self.summary(checksums=checksums), file=file) @cached_property diff --git a/src/depiction/persistence/imzml_reader.py b/src/depiction/persistence/imzml_reader.py index 664bf5d..8543c15 100644 --- a/src/depiction/persistence/imzml_reader.py +++ b/src/depiction/persistence/imzml_reader.py @@ -10,6 +10,7 @@ from depiction.persistence.imzml_mode_enum import ImzmlModeEnum if TYPE_CHECKING: + from types import TracebackType from pathlib import Path from numpy.typing import NDArray @@ -60,7 +61,7 @@ def __getstate__(self) -> dict[str, Any]: } # TODO - def __setstate__(self, state: dict[str, Any]): + def __setstate__(self, state: dict[str, Any]) -> None: # self._portable_reader = state["portable_reader"] self._imzml_path = state["imzml_path"] self._ibd_file = None @@ -100,7 +101,9 @@ def ibd_mmap(self) -> mmap.mmap: def __enter__(self) -> ImzmlReader: return self - def __exit__(self, exc_type, exc_val, exc_tb): + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> None: self.close() def close(self) -> None: diff --git a/src/depiction/persistence/imzml_write_file.py b/src/depiction/persistence/imzml_write_file.py index 7901969..78c21ea 100644 --- a/src/depiction/persistence/imzml_write_file.py +++ b/src/depiction/persistence/imzml_write_file.py @@ -1,9 +1,13 @@ -from contextlib import contextmanager +from __future__ import annotations +from contextlib import contextmanager, AbstractContextManager from pathlib import Path +from typing import TYPE_CHECKING -from depiction.persistence.imzml_mode_enum import ImzmlModeEnum from depiction.persistence.imzml_writer import ImzmlWriter +if TYPE_CHECKING: + from depiction.persistence.imzml_mode_enum import ImzmlModeEnum + class ImzmlWriteFile: """A handle for a .imzML file that is to be written. @@ -38,7 +42,7 @@ def imzml_mode(self) -> ImzmlModeEnum: return self._imzml_mode @contextmanager - def writer(self): + def writer(self) -> AbstractContextManager[ImzmlWriter]: """Opens the .imzML file for writing and yields an `ImzmlWriter` instance.""" if self._write_mode == "x": if self.imzml_file.exists(): diff --git a/src/depiction/persistence/imzml_writer.py b/src/depiction/persistence/imzml_writer.py index 6fd20cf..bb493aa 100644 --- a/src/depiction/persistence/imzml_writer.py +++ b/src/depiction/persistence/imzml_writer.py @@ -1,8 +1,7 @@ +from __future__ import annotations from pathlib import Path -from typing import Optional, TYPE_CHECKING -from collections.abc import Sequence +from typing import TYPE_CHECKING -import numpy as np import pyimzml import pyimzml.ImzMLWriter from tqdm import tqdm @@ -11,6 +10,8 @@ from depiction.persistence.imzml_mode_enum import ImzmlModeEnum if TYPE_CHECKING: + from collections.abc import Sequence + import numpy as np from depiction.persistence.imzml_reader import ImzmlReader @@ -19,13 +20,13 @@ def __init__( self, *, wrapped_imzml_writer: pyimzml.ImzMLWriter.ImzMLWriter, - imzml_alignment_tracker: Optional[ImzmlAlignmentTracker], + imzml_alignment_tracker: ImzmlAlignmentTracker | None, ) -> None: self._imzml_writer = wrapped_imzml_writer self._imzml_alignment_tracker = imzml_alignment_tracker @classmethod - def open(cls, path: str | Path, imzml_mode: ImzmlModeEnum, imzml_alignment_tracking: bool = True): + def open(cls, path: str | Path, imzml_mode: ImzmlModeEnum, imzml_alignment_tracking: bool = True) -> ImzmlWriter: """Opens an imzML file.""" imzml_alignment_tracker = ImzmlAlignmentTracker() if imzml_alignment_tracking else None return cls( @@ -37,7 +38,8 @@ def open(cls, path: str | Path, imzml_mode: ImzmlModeEnum, imzml_alignment_track ) # TODO this currently has a bug, when closing a reader to which not a single spectrum was added. - # it should be handled gracefully, since there are reasonable cases where this could occur with the use of "with" clauses. + # it should be handled gracefully, since there are reasonable cases, + # where this could occur with the use of "with" clauses. def close(self) -> None: self._imzml_writer.close() @@ -75,20 +77,19 @@ def add_spectrum( if self._imzml_alignment_tracker: self._imzml_alignment_tracker.track_mz_array(mz_arr) - if self.imzml_mode == ImzmlModeEnum.CONTINUOUS and self._imzml_alignment_tracker: - if not self.is_aligned: - raise ValueError( - "The m/z array of the first spectrum must be identical to the m/z array of all other spectra!" - ) + if self.imzml_mode == ImzmlModeEnum.CONTINUOUS and self._imzml_alignment_tracker and not self.is_aligned: + raise ValueError( + "The m/z array of the first spectrum must be identical to the m/z array of all other spectra!" + ) # Write the spectrum. self._imzml_writer.addSpectrum(mz_arr, int_arr, coordinates) def copy_spectra( self, - reader: "ImzmlReader", + reader: ImzmlReader, spectra_indices: Sequence[int], - tqdm_position: Optional[int] = None, + tqdm_position: int | None = None, ) -> None: """ Copies spectra from an existing reader. Not optimized yet. @@ -97,12 +98,12 @@ def copy_spectra( """ if tqdm_position is not None: - def progress_fn(x): + def progress_fn(x: Sequence[int]) -> tqdm: return tqdm(x, desc=" spectrum", position=tqdm_position) else: - def progress_fn(x): + def progress_fn(x: Sequence[int]) -> Sequence[int]: return x for spectrum_index in progress_fn(spectra_indices): diff --git a/src/depiction/persistence/ram_reader.py b/src/depiction/persistence/ram_reader.py index 77438d2..38dab73 100644 --- a/src/depiction/persistence/ram_reader.py +++ b/src/depiction/persistence/ram_reader.py @@ -1,13 +1,20 @@ -from typing import Any, NoReturn +from __future__ import annotations + +from typing import Any, NoReturn, TYPE_CHECKING import numpy as np -from numpy._typing import NDArray from depiction.persistence import ImzmlModeEnum +if TYPE_CHECKING: + from types import TracebackType + from numpy.typing import NDArray + class RamReader: - def __init__(self, mz_arr_list, int_arr_list, coordinates) -> None: + def __init__( + self, mz_arr_list: list[NDArray[float]], int_arr_list: list[NDArray[float]], coordinates: NDArray[int] + ) -> None: self._mz_arr_list = mz_arr_list self._int_arr_list = int_arr_list self._coordinates = coordinates @@ -27,10 +34,12 @@ def ibd_mmap(self) -> NoReturn: # TODO a problem, right? raise NotImplementedError - def __enter__(self): + def __enter__(self) -> RamReader: return self - def __exit__(self, exc_type, exc_val, exc_tb): + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> None: self.close() def close(self) -> None: @@ -55,11 +64,11 @@ def n_spectra(self) -> int: return len(self._mz_arr_list) @property - def coordinates(self): + def coordinates(self) -> NDArray[int]: return self._coordinates @property - def coordinates_2d(self): + def coordinates_2d(self) -> NDArray[int]: return self._coordinates[:, :2] def get_spectrum(self, i_spectrum: int) -> tuple[np.ndarray, np.ndarray]: @@ -76,7 +85,7 @@ def get_spectra(self, i_spectra: list[int]) -> tuple[np.ndarray | list[np.ndarra def get_spectrum_mz(self, i_spectrum: int) -> NDArray[float]: return self._mz_arr_list[i_spectrum] - def get_spectrum_int(self, i_spectrum) -> NDArray[float]: + def get_spectrum_int(self, i_spectrum: int) -> NDArray[float]: return self._int_arr_list[i_spectrum] def get_spectrum_n_points(self, i_spectrum: int) -> int: diff --git a/src/depiction/tools/split_imzml.py b/src/depiction/tools/split_imzml.py index 24202d2..d59e02e 100644 --- a/src/depiction/tools/split_imzml.py +++ b/src/depiction/tools/split_imzml.py @@ -2,7 +2,6 @@ import logging import os -from pathlib import Path from typing import Optional import numpy as np diff --git a/src/depiction/visualize/plot_mass_spectra_samples.py b/src/depiction/visualize/plot_mass_spectra_samples.py index b20aad5..17aa004 100644 --- a/src/depiction/visualize/plot_mass_spectra_samples.py +++ b/src/depiction/visualize/plot_mass_spectra_samples.py @@ -27,7 +27,7 @@ def __init__(self, data_df: pl.DataFrame) -> None: self._data_df = data_df self._charts = [] - def plot_spectrum(self, spectrum_name: str): + def plot_spectrum(self, spectrum_name: str) -> None: data = self._data_df.filter(spectrum_name=spectrum_name) chart = ( alt.Chart(data)