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

Prototype type hints for skimage.filters with mypy #7185

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .directory
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Dolphin]
PreviewsShown=false
Timestamp=2023,9,17,13,54,2.458
Version=4
ViewMode=1
138 changes: 138 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@

[mypy]
allow_redefinition = True
strict_optional = False

# External libraries
[mypy-scipy.*]
ignore_missing_imports = True
[mypy-pooch.*]
ignore_missing_imports = True
[mypy-networkx.*]
ignore_missing_imports = True
[mypy-matplotlib.*]
ignore_missing_imports = True
[mypy-sklearn.*]
ignore_missing_imports = True
[mypy-pywt.*]
ignore_missing_imports = True
[mypy-pyamg.*]
ignore_missing_imports = True
[mypy-numpydoc.*]
ignore_missing_imports = True
[mypy-PIL.*]
ignore_missing_imports = True
[mypy-tifffile.*]
ignore_missing_imports = True

# Cython files
[mypy-skimage.util._remap]
ignore_missing_imports = True
[mypy-skimage.filters._multiotsu]
ignore_missing_imports = True
[mypy-skimage.filters.rank.bilateral_cy]
ignore_missing_imports = True
[mypy-skimage.filters.rank.generic_cy]
ignore_missing_imports = True
[mypy-skimage.filters.rank.core_cy]
ignore_missing_imports = True
[mypy-skimage.filters.rank.core_cy_3d]
ignore_missing_imports = True
[mypy-skimage.filters.rank.percentile_cy]
ignore_missing_imports = True
[mypy-skimage.restoration._rolling_ball_cy]
ignore_missing_imports = True
[mypy-skimage.restoration._unwrap_1d]
ignore_missing_imports = True
[mypy-skimage.restoration._denoise_cy]
ignore_missing_imports = True
[mypy-skimage.restoration._nl_means_denoising]
ignore_missing_imports = True
[mypy-skimage.restoration._unwrap_2d]
ignore_missing_imports = True
[mypy-skimage.restoration._inpaint]
ignore_missing_imports = True
[mypy-skimage.restoration._unwrap_3d]
ignore_missing_imports = True
[mypy-skimage.io._plugins._histograms]
ignore_missing_imports = True
[mypy-skimage.io._plugins._colormixer]
ignore_missing_imports = True
[mypy-skimage.feature.censure_cy]
ignore_missing_imports = True
[mypy-skimage.feature.corner_cy]
ignore_missing_imports = True
[mypy-skimage.feature.orb_cy]
ignore_missing_imports = True
[mypy-skimage.feature._canny_cy]
ignore_missing_imports = True
[mypy-skimage.feature._hoghistogram]
ignore_missing_imports = True
[mypy-skimage.feature._sift]
ignore_missing_imports = True
[mypy-skimage.feature._texture]
ignore_missing_imports = True
[mypy-skimage.feature._haar]
ignore_missing_imports = True
[mypy-skimage.feature.brief_cy]
ignore_missing_imports = True
[mypy-skimage.feature._hessian_det_appx]
ignore_missing_imports = True
[mypy-skimage.feature._cascade]
ignore_missing_imports = True
[mypy-skimage.morphology._extrema_cy]
ignore_missing_imports = True
[mypy-skimage.morphology._skeletonize_cy]
ignore_missing_imports = True
[mypy-skimage.morphology._max_tree]
ignore_missing_imports = True
[mypy-skimage.morphology._grayreconstruct]
ignore_missing_imports = True
[mypy-skimage.morphology._flood_fill_cy]
ignore_missing_imports = True
[mypy-skimage.morphology._convex_hull]
ignore_missing_imports = True
[mypy-skimage._shared.transform]
ignore_missing_imports = True
[mypy-skimage._shared.fast_exp]
ignore_missing_imports = True
[mypy-skimage._shared.interpolation]
ignore_missing_imports = True
[mypy-skimage._shared.geometry]
ignore_missing_imports = True
[mypy-skimage.draw._draw]
ignore_missing_imports = True
[mypy-skimage.measure._moments_cy]
ignore_missing_imports = True
[mypy-skimage.measure._find_contours_cy]
ignore_missing_imports = True
[mypy-skimage.measure._pnpoly]
ignore_missing_imports = True
[mypy-skimage.measure._marching_cubes_lewiner_cy]
ignore_missing_imports = True
[mypy-skimage.measure._ccomp]
ignore_missing_imports = True
[mypy-skimage.morphology._skeletonize_3d_cy]
ignore_missing_imports = True
[mypy-skimage.transform._radon_transform]
ignore_missing_imports = True
[mypy-skimage.transform._warps_cy]
ignore_missing_imports = True
[mypy-skimage.transform._hough_transform]
ignore_missing_imports = True
[mypy-skimage.graph._ncut_cy]
ignore_missing_imports = True
[mypy-skimage.graph.heap]
ignore_missing_imports = True
[mypy-skimage.graph._spath]
ignore_missing_imports = True
[mypy-skimage.graph._mcp]
ignore_missing_imports = True
[mypy-skimage.segmentation._slic]
ignore_missing_imports = True
[mypy-skimage.segmentation._watershed_cy]
ignore_missing_imports = True
[mypy-skimage.segmentation._quickshift_cy]
ignore_missing_imports = True
[mypy-skimage.segmentation._felzenszwalb_cy]
ignore_missing_imports = True
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ test = [
'pytest-cov>=2.11.0',
'pytest-localserver',
'pytest-faulthandler',
'mypy',
]

[project.urls]
Expand Down
1 change: 1 addition & 0 deletions requirements/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ pytest>=7.0
pytest-cov>=2.11.0
pytest-localserver
pytest-faulthandler
mypy
2 changes: 2 additions & 0 deletions skimage/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,5 @@ from . import (
transform,
util,
)

__version__ = ""
10 changes: 6 additions & 4 deletions skimage/_shared/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,16 @@
arch32 = struct.calcsize("P") * 8 == 32


_error_on_warnings = os.environ.get('SKIMAGE_TEST_STRICT_WARNINGS_GLOBAL', '0')
if _error_on_warnings.lower() == 'true':
SKIMAGE_TEST_STRICT_WARNINGS_GLOBAL = os.environ.get(
'SKIMAGE_TEST_STRICT_WARNINGS_GLOBAL', '0'
)
if SKIMAGE_TEST_STRICT_WARNINGS_GLOBAL.lower() == 'true':
_error_on_warnings = True
elif _error_on_warnings.lower() == 'false':
elif SKIMAGE_TEST_STRICT_WARNINGS_GLOBAL.lower() == 'false':
_error_on_warnings = False
else:
try:
_error_on_warnings = bool(int(_error_on_warnings))
_error_on_warnings = bool(int(SKIMAGE_TEST_STRICT_WARNINGS_GLOBAL))
except ValueError:
_error_on_warnings = False

Expand Down
2 changes: 1 addition & 1 deletion skimage/_shared/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class _DecoratorBaseClass:
`stacklevel = 1 + stack_length - stack_rank`.
"""

_stack_length = {}
_stack_length: dict = {}

def get_stack_length(self, func):
return self._stack_length.get(func.__name__, _get_stack_length(func))
Expand Down
2 changes: 1 addition & 1 deletion skimage/exposure/exposure.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
]


DTYPE_RANGE = dtype_range.copy()
DTYPE_RANGE: dict = dtype_range.copy()
DTYPE_RANGE.update((d.__name__, limits) for d, limits in dtype_range.items())
DTYPE_RANGE.update(
{
Expand Down
2 changes: 1 addition & 1 deletion skimage/feature/_hog.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np

from . import _hoghistogram
from . import _hoghistogram # type: ignore
from .._shared import utils


Expand Down
2 changes: 1 addition & 1 deletion skimage/filters/rank/_percentile.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"""

from ..._shared.utils import check_nD
from . import percentile_cy
from . import percentile_cy # type: ignore
from .generic import _preprocess_input

__all__ = [
Expand Down
2 changes: 1 addition & 1 deletion skimage/filters/rank/bilateral.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"""

from ..._shared.utils import check_nD
from . import bilateral_cy
from . import bilateral_cy # type: ignore
from .generic import _preprocess_input

__all__ = ['mean_bilateral', 'pop_bilateral', 'sum_bilateral']
Expand Down
2 changes: 1 addition & 1 deletion skimage/filters/rank/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
from ..._shared.utils import check_nD, warn
from ...morphology.footprints import _footprint_is_sequence
from ...util import img_as_ubyte
from . import generic_cy
from . import generic_cy # type: ignore


__all__ = [
Expand Down
2 changes: 1 addition & 1 deletion skimage/filters/tests/test_ridges.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import pytest
from numpy.testing import assert_allclose, assert_array_less, assert_equal

from skimage import img_as_float
from skimage.util import img_as_float
from skimage._shared.utils import _supported_float_type
from skimage.color import rgb2gray
from skimage.data import camera, retina
Expand Down
2 changes: 1 addition & 1 deletion skimage/future/trainable_segmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
except ImportError:
has_sklearn = False

class NotFittedError(Exception):
class NotFittedError(Exception): # type: ignore
pass


Expand Down
3 changes: 2 additions & 1 deletion skimage/graph/_graph_cut.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from scipy.sparse import linalg

from .._shared.utils import deprecate_kwarg
from . import _ncut, _ncut_cy
from . import _ncut
from . import _ncut_cy # type: ignore


def cut_threshold(labels, rag, thresh, in_place=True):
Expand Down
2 changes: 1 addition & 1 deletion skimage/graph/_ncut.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import networkx as nx
import numpy as np
from scipy import sparse
from . import _ncut_cy
from . import _ncut_cy # type: ignore


def DW_matrices(graph):
Expand Down
2 changes: 1 addition & 1 deletion skimage/graph/spath.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import numpy as np
from . import _spath
from . import _spath # type: ignore


def shortest_path(arr, reach=1, axis=-1, output_indexlist=False):
Expand Down
2 changes: 1 addition & 1 deletion skimage/measure/_marching_cubes_lewiner.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import numpy as np

from . import _marching_cubes_lewiner_luts as mcluts
from . import _marching_cubes_lewiner_cy
from . import _marching_cubes_lewiner_cy # type: ignore


def marching_cubes(
Expand Down
2 changes: 1 addition & 1 deletion skimage/measure/_moments.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import numpy as np

from .._shared.utils import _supported_float_type, check_nD
from . import _moments_cy
from . import _moments_cy # type: ignore
from ._moments_analytical import moments_raw_to_central


Expand Down
2 changes: 1 addition & 1 deletion skimage/morphology/max_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from ._util import _validate_connectivity, _offsets_to_raveled_neighbors
from ..util import invert

from . import _max_tree
from . import _max_tree # type: ignore

unsigned_int_types = [np.uint8, np.uint16, np.uint32, np.uint64]
signed_int_types = [np.int8, np.int16, np.int32, np.int64]
Expand Down
31 changes: 19 additions & 12 deletions skimage/restoration/_cycle_spin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import typing as ty
from itertools import product

import numpy as np
from numpy.typing import ArrayLike
from .._shared import utils
from .._shared.utils import warn

Expand All @@ -11,7 +14,12 @@
dask_available = False


def _generate_shifts(ndim, multichannel, max_shifts, shift_steps=1):
def _generate_shifts(
ndim: int,
multichannel: bool,
max_shifts: int | tuple[int, ...],
shift_steps: int | tuple[int, ...] = 1,
) -> product[tuple[int, ...]]:
"""Returns all combinations of shifts in n dimensions over the specified
max_shifts and step sizes.

Expand All @@ -22,14 +30,14 @@ def _generate_shifts(ndim, multichannel, max_shifts, shift_steps=1):
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
"""
mc = int(multichannel)
if np.isscalar(max_shifts):
if isinstance(max_shifts, int):
max_shifts = (max_shifts,) * (ndim - mc) + (0,) * mc
elif multichannel and len(max_shifts) == ndim - 1:
max_shifts = tuple(max_shifts) + (0,)
elif len(max_shifts) != ndim:
raise ValueError("max_shifts should have length ndim")

if np.isscalar(shift_steps):
if isinstance(shift_steps, int):
shift_steps = (shift_steps,) * (ndim - mc) + (1,) * mc
elif multichannel and len(shift_steps) == ndim - 1:
shift_steps = tuple(shift_steps) + (1,)
Expand All @@ -49,15 +57,15 @@ def _generate_shifts(ndim, multichannel, max_shifts, shift_steps=1):

@utils.channel_as_last_axis()
def cycle_spin(
x,
func,
max_shifts,
shift_steps=1,
num_workers=None,
func_kw=None,
x: ArrayLike,
func: ty.Callable,
max_shifts: int | tuple[int, ...],
shift_steps: int | tuple[int, ...] = 1,
num_workers: int = None,
func_kw: dict = None,
*,
channel_axis=None,
):
channel_axis: int = None,
) -> np.ndarray:
"""Cycle spinning (repeatedly apply func to shifted versions of x).

Parameters
Expand Down Expand Up @@ -128,7 +136,6 @@ def cycle_spin(
"""
if func_kw is None:
func_kw = {}

x = np.asanyarray(x)
multichannel = channel_axis is not None
all_shifts = _generate_shifts(x.ndim, multichannel, max_shifts, shift_steps)
Expand Down
2 changes: 1 addition & 1 deletion skimage/segmentation/_watershed.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import numpy as np
from scipy import ndimage as ndi

from . import _watershed_cy
from . import _watershed_cy # type: ignore
from ..morphology.extrema import local_minima
from ..morphology._util import _validate_connectivity, _offsets_to_raveled_neighbors
from ..util import crop, regular_seeds
Expand Down