Skip to content

Commit

Permalink
Remove code needed to support Python < 3.9 and apply ruff's pyupgrade…
Browse files Browse the repository at this point in the history
… rules (#725)

`math.prod` was added in Python 3.8
`math.lcm` was added in Python 3.9

`pyproject.toml` was updated to have `ruff` also check [pyupgrade rules](https://docs.astral.sh/ruff/rules/#pyupgrade-up)

Authors:
  - Gregory Lee (https://github.com/grlee77)

Approvers:
  - https://github.com/jakirkham

URL: #725
  • Loading branch information
grlee77 authored Apr 18, 2024
1 parent 16d015b commit 3e67c2f
Show file tree
Hide file tree
Showing 40 changed files with 133 additions and 244 deletions.
2 changes: 1 addition & 1 deletion python/cucim/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ testpaths = [

[tool.ruff]
# see: https://docs.astral.sh/ruff/rules/
select = ["E", "F", "W", "I"]
select = ["E", "F", "W", "I", "UP"]
fixable = ["ALL"]
exclude = [
# TODO: Remove this in a follow-up where we fix __all__.
Expand Down
11 changes: 2 additions & 9 deletions python/cucim/src/cucim/_misc.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
"""Misc utility functions that are not from SciPy, NumPy or scikit-image.
"""
import math

import numpy

if hasattr(math, "prod"):
prod = math.prod # available in Python 3.8+ only
else:
prod = numpy.prod
import numpy as np


def ndim(a):
Expand Down Expand Up @@ -46,4 +39,4 @@ def ndim(a):
try:
return a.ndim
except AttributeError:
return numpy.asarray(a).ndim
return np.asarray(a).ndim
2 changes: 1 addition & 1 deletion python/cucim/src/cucim/clara/converter/tiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def svs2tif(
width, height = slide_dimensions
img_w, img_h = width, height
for level in range(tiles.level_count):
memmap_filename = Path(output_folder, "level{}.mmap".format(level))
memmap_filename = Path(output_folder, f"level{level}.mmap")
memmap_shape = (img_h, img_w, 3)
np_memmap_arr = np.memmap(
memmap_filename, dtype=np.uint8, mode="w+", shape=memmap_shape
Expand Down
30 changes: 12 additions & 18 deletions python/cucim/src/cucim/core/operations/color/jitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

import numbers
from typing import Any, List, Optional, Tuple
from typing import Any, Optional

import cupy
import numpy as np
Expand All @@ -29,25 +29,19 @@ def _check_input(
if isinstance(value, numbers.Number):
if value < 0:
raise ValueError(
"If {} is a single number, \
it must be non negative.".format(
name
)
f"If {name} is a single number, \
it must be non negative."
)
value = [center - float(value), center + float(value)]
if clip_first_on_zero:
value[0] = max(value[0], 0.0)
elif isinstance(value, (tuple, list)) and len(value) == 2:
if not bound[0] <= value[0] <= value[1] <= bound[1]:
raise ValueError(
"{} values should be between {}".format(name, bound)
)
raise ValueError(f"{name} values should be between {bound}")
else:
raise TypeError(
"{} should be a single number or a \
list/tuple with length 2.".format(
name
)
f"{name} should be a single number or a \
list/tuple with length 2."
)
# if value is 0 or (1., 1.) for brightness/contrast/saturation
# or (0., 0.) for hue, do nothing
Expand All @@ -57,11 +51,11 @@ def _check_input(


def _get_params(
brightness: Optional[List[float]],
contrast: Optional[List[float]],
saturation: Optional[List[float]],
hue: Optional[List[float]],
) -> Tuple[
brightness: Optional[list[float]],
contrast: Optional[list[float]],
saturation: Optional[list[float]],
hue: Optional[list[float]],
) -> tuple[
np.ndarray,
Optional[float],
Optional[float],
Expand Down Expand Up @@ -184,7 +178,7 @@ def _adjust_saturation(input_arr, saturation):
# hue jitter
def _adjust_hue(input_arr, hue):
if not (-0.5 <= hue <= 0.5):
raise ValueError("hue factor({}) is not in [-0.5, 0.5].".format(hue))
raise ValueError(f"hue factor({hue}) is not in [-0.5, 0.5].")

if len(input_arr.shape) == 4:
N, C, H, W = input_arr.shape
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import math
from typing import Any

import cupy
Expand Down Expand Up @@ -108,7 +109,7 @@ def normalize_data(
value_range = max_value - min_value
norm_factor = norm_constant / value_range

total_size = int(np.prod(img.shape))
total_size = int(math.prod(img.shape))
blockx = 128
gridx = int((total_size - 1) / blockx + 1)

Expand Down
3 changes: 2 additions & 1 deletion python/cucim/src/cucim/core/operations/intensity/scaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import math
from typing import Any

import cupy
Expand Down Expand Up @@ -100,7 +101,7 @@ def scale_intensity_range(
b_min = float("-inf")

sh = img.shape
total_size = np.prod(sh)
total_size = math.prod(sh)
blockx = 128
gridx = int((total_size - 1) / blockx + 1)

Expand Down
3 changes: 2 additions & 1 deletion python/cucim/src/cucim/core/operations/intensity/zoom.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
# limitations under the License.

import math
from typing import Any, Sequence, Union
from collections.abc import Sequence
from typing import Any, Union

import cupy
import numpy as np
Expand Down
34 changes: 2 additions & 32 deletions python/cucim/src/cucim/core/operations/morphology/_pba_2d.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,11 @@
import functools
import math
import numbers
import os

import cupy

from cucim.skimage._vendored import pad
from cucim.skimage._vendored._ndimage_util import _get_inttype

try:
# math.lcm was introduced in Python 3.9
from math import lcm
except ImportError:
"""Fallback implementation of least common multiple (lcm)
TODO: remove once minimum Python requirement is >= 3.9
"""

def _lcm(a, b):
return abs(b * (a // math.gcd(a, b)))

@functools.lru_cache()
def lcm(*args):
nargs = len(args)
if not all(isinstance(a, numbers.Integral) for a in args):
raise TypeError("all arguments must be integers")
if nargs == 0:
return 1
res = int(args[0])
if nargs == 1:
return abs(res)
for i in range(1, nargs):
x = int(args[i])
res = _lcm(res, x)
return res


pba2d_defines_template = """
// MARKER is used to mark blank pixels in the texture.
Expand Down Expand Up @@ -76,7 +46,7 @@ def get_pba2d_src(block_size_2d=64, marker=-32768, pixel_int2_t="short2"):
make_pixel_func=make_pixel_func,
)
kernel_directory = os.path.join(os.path.dirname(__file__), "cuda")
with open(os.path.join(kernel_directory, "pba_kernels_2d.h"), "rt") as f:
with open(os.path.join(kernel_directory, "pba_kernels_2d.h")) as f:
pba2d_kernels = "\n".join(f.readlines())

pba2d_code += pba2d_kernels
Expand Down Expand Up @@ -312,7 +282,7 @@ def _pba_2d(
m1, m2, m3 = block_params
if math.log2(m2) % 1 > 1e-5:
raise ValueError("m2 must be a power of 2")
multiple = lcm(block_size, m1, m2, m3)
multiple = math.lcm(block_size, m1, m2, m3)
padded_size = math.ceil(max(arr.shape) / multiple) * multiple

if m1 > padded_size // block_size:
Expand Down
5 changes: 2 additions & 3 deletions python/cucim/src/cucim/core/operations/morphology/_pba_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
_generate_indices_ops,
_generate_shape,
_get_block_size,
lcm,
)

pba3d_defines_template = """
Expand Down Expand Up @@ -85,7 +84,7 @@ def get_pba3d_src(
else:
pba3d_code += pba3d_defines_encode_32bit
kernel_directory = os.path.join(os.path.dirname(__file__), "cuda")
with open(os.path.join(kernel_directory, "pba_kernels_3d.h"), "rt") as f:
with open(os.path.join(kernel_directory, "pba_kernels_3d.h")) as f:
pba3d_kernels = "\n".join(f.readlines())
pba3d_code += pba3d_kernels
return pba3d_code
Expand Down Expand Up @@ -188,7 +187,7 @@ def decode3d(encoded, size_max=1024):
def _determine_padding(shape, block_size, m1, m2, m3, blockx, blocky):
# TODO: can possibly revise to consider only particular factors for LCM on
# a given axis
LCM = lcm(block_size, m1, m2, m3, blockx, blocky)
LCM = math.lcm(block_size, m1, m2, m3, blockx, blocky)
orig_sz, orig_sy, orig_sx = shape
round_up = False
if orig_sx % LCM != 0:
Expand Down
12 changes: 0 additions & 12 deletions python/cucim/src/cucim/skimage/_vendored/_internal.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import math
from functools import reduce
from operator import mul

import cupy

# TODO: when minimum numpy dependency is 1.25 use:
Expand Down Expand Up @@ -72,11 +68,3 @@ def _normalize_axis_indices(axes, ndim): # NOQA
res.append(axis)

return tuple(sorted(res))


if hasattr(math, "prod"):
prod = math.prod
else:

def prod(iterable, *, start=1):
return reduce(mul, iterable, start)
37 changes: 16 additions & 21 deletions python/cucim/src/cucim/skimage/_vendored/_ndimage_filters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""A vendored subset of cupyx.scipy.ndimage._filters"""
import math
import warnings

import cupy
Expand Down Expand Up @@ -1181,7 +1182,7 @@ def _get_min_or_max_kernel(
ctype = "X" if has_weights else "double"
value = "{value}"
if not has_weights:
value = "cast<double>({})".format(value)
value = f"cast<double>({value})"

# Having a non-flat structure biases the values
if has_structure:
Expand Down Expand Up @@ -1386,7 +1387,7 @@ def _rank_filter(
has_weights = True
if sizes is not None:
has_weights = False
filter_size = internal.prod(sizes)
filter_size = math.prod(sizes)
if filter_size == 0:
return cupy.zeros_like(input)
footprint_shape = tuple(sizes)
Expand Down Expand Up @@ -1497,45 +1498,39 @@ def _get_rank_kernel(
else:
comp_op = ">"
array_size = s_rank + 2
found_post = """
if (iv > {rank} + 1) {{{{
found_post = f"""
if (iv > {s_rank} + 1) {{{{
int target_iv = 0;
X target_val = values[0];
for (int jv = 1; jv <= {rank} + 1; jv++) {{{{
for (int jv = 1; jv <= {s_rank} + 1; jv++) {{{{
if (target_val {comp_op} values[jv]) {{{{
target_val = values[jv];
target_iv = jv;
}}}}
}}}}
if (target_iv <= {rank}) {{{{
values[target_iv] = values[{rank} + 1];
if (target_iv <= {s_rank}) {{{{
values[target_iv] = values[{s_rank} + 1];
}}}}
iv = {rank} + 1;
}}}}""".format(
rank=s_rank, comp_op=comp_op
)
post = """
iv = {s_rank} + 1;
}}}}"""
post = f"""
X target_val = values[0];
for (int jv = 1; jv <= {rank}; jv++) {{
for (int jv = 1; jv <= {s_rank}; jv++) {{
if (target_val {comp_op} values[jv]) {{
target_val = values[jv];
}}
}}
y=cast<Y>(target_val);""".format(
rank=s_rank, comp_op=comp_op
)
y=cast<Y>(target_val);"""
sorter = ""
else:
array_size = filter_size
found_post = ""
post = "sort(values,{});\ny=cast<Y>(values[{}]);".format(
filter_size, rank
)
post = f"sort(values,{filter_size});\ny=cast<Y>(values[{rank}]);"
sorter = __SHELL_SORT.format(gap=_get_shell_gap(filter_size))

return _filters_core._generate_nd_kernel(
"rank_{}_{}".format(filter_size, rank),
"int iv = 0;\nX values[{}];".format(array_size),
f"rank_{filter_size}_{rank}",
f"int iv = 0;\nX values[{array_size}];",
"values[iv++] = {value};" + found_post,
post,
mode,
Expand Down
Loading

0 comments on commit 3e67c2f

Please sign in to comment.