Skip to content

Commit

Permalink
Merge pull request #165 from fmi-faim/code-style-refactor
Browse files Browse the repository at this point in the history
Fix various code style issues
  • Loading branch information
imagejan authored Jul 30, 2024
2 parents 47969d6 + d008b11 commit 66e3607
Show file tree
Hide file tree
Showing 59 changed files with 1,373 additions and 1,538 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.9', '3.10', '3.11', '3.12']
python-version: ['3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v3
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,4 @@ mobie-example-project/

# scratchpad
scratchpad/
.pixi
94 changes: 54 additions & 40 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,33 @@ name = "faim-ipa"
dynamic = ["version"]
description = 'Tools used at FMI-FAIM for Image Processing and Analysis.'
readme = "README.md"
requires-python = ">=3.9"
requires-python = ">=3.10"
license = "BSD-3-Clause"
keywords = []
authors = [
{ name = "Tim-Oliver Buchholz", email = "tim-oliver.buchholz@fmi.ch" },
{ name = "Jan Eglinger", email = "jan.eglinger@fmi.ch" },
{name = "Tim-Oliver Buchholz", email = "tim-oliver.buchholz@fmi.ch"},
{name = "Jan Eglinger", email = "jan.eglinger@fmi.ch"},
]
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
dependencies = [
"pydantic",
"defusedxml",
"distributed",
"numpy<2",
"matplotlib",
"scikit-image",
"pandas",
"numpy<2",
"ome-zarr",
"pandas",
"pint",
"pydantic>=2",
"scikit-image",
"tqdm",
"pint"
]

[project.urls]
Expand All @@ -43,14 +43,46 @@ Homepage = "https://github.com/fmi-faim/faim-ipa.git"
"Source Code" = "https://github.com/fmi-faim/faim-ipa"
"User Support" = "https://github.com/fmi-faim/faim-ipa/issues"

[tool.hatch.version]
source = "vcs"
[tool.coverage.paths]
faim_ipa = ["src/faim_ipa", "*/faim-ipa/src/faim_ipa"]
tests = ["tests", "*/faim-ipa/tests"]

[tool.coverage.report]
show_missing = true
exclude_lines = [
"no cov",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
]

[tool.coverage.run]
source_pkgs = ["faim_ipa", "tests"]
branch = true
parallel = true
omit = [
"src/faim_ipa/__about__.py",
]

[tool.hatch.build.targets.sdist]
exclude = [
"/examples",
"/resources",
"*/__pycache__",
"/tests",
"/scratchpad",
"/.github",
".pre-commit-config.yaml",
]

[[tool.hatch.envs.all.matrix]]
python = ["3.10", "3.11", "3.12"]

[tool.hatch.envs.default]
dependencies = [
"coverage[toml]>=6.5",
"pytest",
]

[tool.hatch.envs.default.scripts]
test = "pytest {args:tests}"
test-cov = "coverage run -m pytest {args:tests}"
Expand All @@ -73,49 +105,31 @@ cov = [
"cov-report",
]

[[tool.hatch.envs.all.matrix]]
python = ["3.9", "3.10", "3.11", "3.12"]

[tool.hatch.envs.types]
dependencies = [
"mypy>=1.0.0",
]

[tool.hatch.envs.types.scripts]
check = "mypy --install-types --non-interactive {args:src/faim_ipa tests}"

[tool.hatch.metadata]
allow-direct-references = true

[tool.hatch.build.targets.sdist]
exclude = [
"/examples",
"/resources",
"*/__pycache__",
"/tests",
"/scratchpad",
"/.github",
".pre-commit-config.yaml",
]
[tool.hatch.version]
source = "vcs"

[tool.coverage.run]
source_pkgs = ["faim_ipa", "tests"]
branch = true
parallel = true
omit = [
"src/faim_ipa/__about__.py",
[tool.pytest.ini_options]
addopts = [
"--import-mode=importlib",
]

[tool.coverage.paths]
faim_ipa = ["src/faim_ipa", "*/faim-ipa/src/faim_ipa"]
tests = ["tests", "*/faim-ipa/tests"]
[tool.ruff.lint]
ignore = ["FA100", "S101"]

[tool.coverage.report]
show_missing = true
exclude_lines = [
"no cov",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
]
[tool.ruff.lint.extend-per-file-ignores]
"**/tests/*" = ["F811", "INP001", "SLF001"]
"**/examples/*" = ["INP001"]

[tool.setuptools_scm]
write_to = "src/faim_ipa/_version.py"
Expand Down
2 changes: 1 addition & 1 deletion src/faim_ipa/alignment/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .alignment import GridAlignment, StageAlignment # noqa: F401
from faim_ipa.alignment.alignment import GridAlignment, StageAlignment # noqa: F401
16 changes: 9 additions & 7 deletions src/faim_ipa/alignment/alignment.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from abc import ABC
from abc import ABC, abstractmethod
from copy import copy

import numpy as np

from faim_ipa.stitching import Tile, stitching_utils
from faim_ipa.stitching import stitching_utils
from faim_ipa.stitching.tile import Tile


class AbstractAlignment(ABC):
Expand All @@ -15,6 +16,7 @@ def __init__(self, tiles: list[Tile]) -> None:
self._unaligned_tiles = stitching_utils.shift_to_origin(tiles)
self._aligned_tiles = self._align(self._unaligned_tiles)

@abstractmethod
def _align(self, tiles: list[Tile]) -> list[Tile]:
raise NotImplementedError

Expand Down Expand Up @@ -45,12 +47,12 @@ def _align(self, tiles: list[Tile]) -> list[Tile]:
grid_positions_x = set()
tile_map = {}
for tile in tiles:
assert (
tile.shape[-2:] == tile_shape[-2:]
), "All tiles must have the same YX shape."
if tile.shape[-2:] != tile_shape[-2:]:
message = f"All tiles must have the same YX shape. {tile.shape[-2:]} <=> {tile_shape[-2:]}"
raise ValueError(message)
y_pos = int(np.round(tile.position.y / tile_shape[-2]))
x_pos = int(np.round(tile.position.x / tile_shape[-1]))
if (y_pos, x_pos) in tile_map.keys():
if (y_pos, x_pos) in tile_map:
tile_map[(y_pos, x_pos)].append(tile)
else:
tile_map[(y_pos, x_pos)] = [tile]
Expand All @@ -61,7 +63,7 @@ def _align(self, tiles: list[Tile]) -> list[Tile]:
grid_positions_x = sorted(grid_positions_x)
for y_pos in grid_positions_y:
for x_pos in grid_positions_x:
if (y_pos, x_pos) in tile_map.keys():
if (y_pos, x_pos) in tile_map:
for unaligned_tile in tile_map[(y_pos, x_pos)]:
new_tile = copy(unaligned_tile)
new_tile.position.y = y_pos * tile_shape[-2]
Expand Down
94 changes: 1 addition & 93 deletions src/faim_ipa/dask_utils.py
Original file line number Diff line number Diff line change
@@ -1,100 +1,8 @@
from multiprocessing import Process, Queue
from time import sleep
from __future__ import annotations

import numpy as np


class LocalClusterFactory:
"""Creates a local dask cluster in a sub-process."""

def __init__(
self,
n_workers: int = None,
threads_per_worker: int = None,
processes: bool = None,
memory_limit: str = None,
local_directory: str = None,
):
self.n_workers = n_workers
self.threads_per_worker = threads_per_worker
self.processes = processes
self.memory_limit = memory_limit
self.local_directory = local_directory
self._queue = Queue(1)
self._scheduler_address = None

self._subprocess = Process(
target=self._run_cluster,
args=(
self._queue,
self.n_workers,
self.threads_per_worker,
self.processes,
self.memory_limit,
self.local_directory,
),
)
self._subprocess.start()
self._scheduler_address = None
self._client = None

def _get_scheduler_address(self):
if self._scheduler_address is None:
scheduler_address = self._queue.get()
self._scheduler_address = scheduler_address
self._queue.close()
self._queue = None

return self._scheduler_address

def _shutdown(self):
if self._client is not None and self._client.scheduler is not None:
self._client.shutdown()
self._client = None

if self._subprocess is not None and self._subprocess.is_alive():
self._subprocess.join()

def __del__(self):
self._shutdown()

@staticmethod
def _run_cluster(
queue: Queue,
n_workers: int,
threads_per_worker: int,
processes: bool,
memory_limit: str,
local_directory: str,
):
import dask
import distributed

dask.config.set({"distributed.workers.memory.spill": 0.90})
dask.config.set({"distributed.workers.memory.target": 0.85})
dask.config.set({"distributed.workers.memory.terminate": 0.98})

client = distributed.Client(
n_workers=n_workers,
threads_per_worker=threads_per_worker,
processes=processes,
memory_limit=memory_limit,
local_directory=local_directory,
)
queue.put(client.cluster.scheduler.address)
while client.cluster.scheduler.status.value != "closed":
sleep(5)

def get_client(self):
"""Get a dask client for the local cluster."""
if self._client is None:
import distributed

self._client = distributed.Client(self._get_scheduler_address())

return self._client


def mean_cast_to(target_dtype):
"""
Wrap np.mean to cast the result to a given dtype.
Expand Down
19 changes: 10 additions & 9 deletions src/faim_ipa/detection/blobs.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Optional
from __future__ import annotations

import numpy as np
from scipy.ndimage import gaussian_laplace
from skimage.feature import peak_local_max
from skimage.morphology import h_maxima, ball
from skimage.util import img_as_float32
from skimage.feature.blob import _prune_blobs
from skimage.morphology import ball, h_maxima
from skimage.util import img_as_float32

from faim_ipa.detection.utils import estimate_log_rescale_factor

Expand All @@ -17,7 +17,7 @@ def detect_blobs(
h: int,
scale_factors: list[int],
overlap: float,
background_img: Optional[np.ndarray] = None,
background_img: np.ndarray | None = None,
) -> np.ndarray:
"""Detect blobs of different sizes.
Expand Down Expand Up @@ -49,10 +49,11 @@ def detect_blobs(
-------
Detected spots.
"""
if background_img is not None:
image = img_as_float32(img) - img_as_float32(background_img)
else:
image = img_as_float32(img)
image = (
img_as_float32(img) - img_as_float32(background_img)
if background_img is not None
else img_as_float32(img)
)

rescale_factor = estimate_log_rescale_factor(
axial_sigma=axial_sigma, lateral_sigma=lateral_sigma
Expand All @@ -62,7 +63,7 @@ def detect_blobs(
(axial_sigma * f, lateral_sigma * f, lateral_sigma * f) for f in scale_factors
]

scale_cube = np.empty(image.shape + (len(sigmas),), dtype=np.uint8)
scale_cube = np.empty((*image.shape, len(sigmas)), dtype=np.uint8)

h_ = img_as_float32(np.array(h, dtype=img.dtype))
scale_norm = np.mean([axial_sigma, lateral_sigma, lateral_sigma])
Expand Down
Loading

0 comments on commit 66e3607

Please sign in to comment.