From d5c528b84efa41e9263aa87f7d90a80cdbcd3e63 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Wed, 16 Oct 2024 14:07:11 +1100 Subject: [PATCH 01/21] `signal`: Add type stubs to `argrel*` functions Namely: 1. `argrelmin` 2. `argrelmax` 3. `argrelextrema` --- scipy-stubs/signal/_peak_finding.pyi | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index 81b7192c..91d6f046 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -1,10 +1,25 @@ +from collections.abc import Callable +from typing import Literal, TypeAlias + +import numpy as np +import numpy.typing as npt from scipy._typing import Untyped __all__ = ["argrelextrema", "argrelmax", "argrelmin", "find_peaks", "find_peaks_cwt", "peak_prominences", "peak_widths"] -def argrelmin(data: Untyped, axis: int = 0, order: int = 1, mode: str = "clip") -> Untyped: ... -def argrelmax(data: Untyped, axis: int = 0, order: int = 1, mode: str = "clip") -> Untyped: ... -def argrelextrema(data: Untyped, comparator: Untyped, axis: int = 0, order: int = 1, mode: str = "clip") -> Untyped: ... +_Mode: TypeAlias = Literal["clip", "wrap"] + +def argrelmin( + data: npt.NDArray[np.generic], axis: int = 0, order: int = 1, mode: _Mode = "clip" +) -> tuple[npt.NDArray[np.intp], ...]: ... +def argrelmax(data: Untyped, axis: int = 0, order: int = 1, mode: _Mode = "clip") -> tuple[npt.NDArray[np.intp], ...]: ... +def argrelextrema( + data: npt.NDArray[np.generic], + comparator: Callable[[npt.NDArray[np.generic], npt.NDArray[np.generic]], npt.NDArray[np.bool_]], + axis: int = 0, + order: int = 1, + mode: _Mode = "clip", +) -> tuple[npt.NDArray[np.intp], ...]: ... def peak_prominences(x: Untyped, peaks: Untyped, wlen: Untyped | None = None) -> Untyped: ... def peak_widths( x: Untyped, From c7733bc11e732439e3589ab4b8ecdfe1164742e6 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Wed, 16 Oct 2024 14:21:52 +1100 Subject: [PATCH 02/21] `signal`: Add type stubs to `peaks_*` functions Namely: 1. `peaks_prominences` 2. `peaks_widths` --- scipy-stubs/signal/_peak_finding.pyi | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index 91d6f046..f633170b 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -8,6 +8,10 @@ from scipy._typing import Untyped __all__ = ["argrelextrema", "argrelmax", "argrelmin", "find_peaks", "find_peaks_cwt", "peak_prominences", "peak_widths"] _Mode: TypeAlias = Literal["clip", "wrap"] +_ProminencesResult: TypeAlias = tuple[npt.NDArray[np.float64], npt.NDArray[np.intp], npt.NDArray[np.intp]] +_WidthsResult: TypeAlias = tuple[ + npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64] +] def argrelmin( data: npt.NDArray[np.generic], axis: int = 0, order: int = 1, mode: _Mode = "clip" @@ -20,14 +24,14 @@ def argrelextrema( order: int = 1, mode: _Mode = "clip", ) -> tuple[npt.NDArray[np.intp], ...]: ... -def peak_prominences(x: Untyped, peaks: Untyped, wlen: Untyped | None = None) -> Untyped: ... +def peak_prominences(x: npt.ArrayLike, peaks: npt.ArrayLike, wlen: int | None = None) -> _ProminencesResult: ... def peak_widths( - x: Untyped, - peaks: Untyped, + x: npt.ArrayLike, + peaks: npt.ArrayLike, rel_height: float = 0.5, - prominence_data: Untyped | None = None, - wlen: Untyped | None = None, -) -> Untyped: ... + prominence_data: _ProminencesResult | None = None, + wlen: int | None = None, +) -> _WidthsResult: ... def find_peaks( x: Untyped, height: Untyped | None = None, From 88ea09c5a635d7d5d932b728aeda419f7e5c3868 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Wed, 16 Oct 2024 18:15:11 +1100 Subject: [PATCH 03/21] `signal`: Add type stubs for `find_peaks` and `find_peaks_cwt` --- scipy-stubs/signal/_peak_finding.pyi | 58 ++++++++++++++++++---------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index f633170b..e56e5a88 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -1,9 +1,9 @@ -from collections.abc import Callable -from typing import Literal, TypeAlias +from collections.abc import Callable, Sequence +from typing import Concatenate, Literal, TypeAlias, TypedDict +from typing_extensions import NotRequired import numpy as np import numpy.typing as npt -from scipy._typing import Untyped __all__ = ["argrelextrema", "argrelmax", "argrelmin", "find_peaks", "find_peaks_cwt", "peak_prominences", "peak_widths"] @@ -13,10 +13,26 @@ _WidthsResult: TypeAlias = tuple[ npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64] ] +class _FindPeaksResultsDict(TypedDict): + peak_heights: NotRequired[npt.NDArray[np.float64]] + left_thresholds: NotRequired[npt.NDArray[np.float64]] + right_thresholds: NotRequired[npt.NDArray[np.float64]] + prominences: NotRequired[npt.NDArray[np.float64]] + left_bases: NotRequired[npt.NDArray[np.intp]] + right_bases: NotRequired[npt.NDArray[np.intp]] + width_heights: NotRequired[npt.NDArray[np.float64]] + left_ips: NotRequired[npt.NDArray[np.float64]] + right_ips: NotRequired[npt.NDArray[np.float64]] + plateau_sizes: NotRequired[npt.NDArray[np.intp]] + left_edges: NotRequired[npt.NDArray[np.intp]] + right_edges: NotRequired[npt.NDArray[np.intp]] + def argrelmin( data: npt.NDArray[np.generic], axis: int = 0, order: int = 1, mode: _Mode = "clip" ) -> tuple[npt.NDArray[np.intp], ...]: ... -def argrelmax(data: Untyped, axis: int = 0, order: int = 1, mode: _Mode = "clip") -> tuple[npt.NDArray[np.intp], ...]: ... +def argrelmax( + data: npt.NDArray[np.generic], axis: int = 0, order: int = 1, mode: _Mode = "clip" +) -> tuple[npt.NDArray[np.intp], ...]: ... def argrelextrema( data: npt.NDArray[np.generic], comparator: Callable[[npt.NDArray[np.generic], npt.NDArray[np.generic]], npt.NDArray[np.bool_]], @@ -33,24 +49,24 @@ def peak_widths( wlen: int | None = None, ) -> _WidthsResult: ... def find_peaks( - x: Untyped, - height: Untyped | None = None, - threshold: Untyped | None = None, - distance: Untyped | None = None, - prominence: Untyped | None = None, - width: Untyped | None = None, - wlen: Untyped | None = None, + x: npt.ArrayLike, + height: float | npt.NDArray[np.float64] | tuple[float | None, float | None] | None = None, + threshold: float | npt.NDArray[np.float64] | tuple[float | None, float | None] | None = None, + distance: np.float64 | None = None, + prominence: float | npt.NDArray[np.float64] | tuple[float | None, float | None] | None = None, + width: float | npt.NDArray[np.float64] | tuple[float | None, float | None] | None = None, + wlen: int | None = None, rel_height: float = 0.5, - plateau_size: Untyped | None = None, -) -> Untyped: ... + plateau_size: float | npt.NDArray[np.intp] | tuple[int | None, int | None] | None = None, +) -> tuple[npt.NDArray[np.intp], _FindPeaksResultsDict]: ... def find_peaks_cwt( - vector: Untyped, - widths: Untyped, - wavelet: Untyped | None = None, - max_distances: Untyped | None = None, - gap_thresh: Untyped | None = None, - min_length: Untyped | None = None, + vector: npt.ArrayLike, + widths: npt.ArrayLike, + wavelet: Callable[Concatenate[int, float, ...], npt.NDArray[np.float64]] | None = None, + max_distances: Sequence[int] | None = None, + gap_thresh: float | None = None, + min_length: int | None = None, min_snr: int = 1, noise_perc: int = 10, - window_size: Untyped | None = None, -) -> Untyped: ... + window_size: int | None = None, +) -> npt.NDArray[np.intp]: ... From d53d73996e5bf077b79b2f4030e1b31189a224e6 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Wed, 16 Oct 2024 18:30:55 +1100 Subject: [PATCH 04/21] `signal`: Fix the type stub for `plateau_size` in `find_peaks` --- scipy-stubs/signal/_peak_finding.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index e56e5a88..f00f4f49 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -57,7 +57,7 @@ def find_peaks( width: float | npt.NDArray[np.float64] | tuple[float | None, float | None] | None = None, wlen: int | None = None, rel_height: float = 0.5, - plateau_size: float | npt.NDArray[np.intp] | tuple[int | None, int | None] | None = None, + plateau_size: int | npt.NDArray[np.intp] | tuple[int | None, int | None] | None = None, ) -> tuple[npt.NDArray[np.intp], _FindPeaksResultsDict]: ... def find_peaks_cwt( vector: npt.ArrayLike, From 731c4d4a47f12aa0ca2ec57662b92521c9dc689a Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Thu, 17 Oct 2024 11:31:58 +1100 Subject: [PATCH 05/21] `signal`: Use `total=False` on `TypedDict` to avoid using `NotRequired` Specifically for `_peak_finding.pyi` --- scipy-stubs/signal/_peak_finding.pyi | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index f00f4f49..1d2cc73f 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -1,6 +1,5 @@ from collections.abc import Callable, Sequence from typing import Concatenate, Literal, TypeAlias, TypedDict -from typing_extensions import NotRequired import numpy as np import numpy.typing as npt @@ -13,19 +12,19 @@ _WidthsResult: TypeAlias = tuple[ npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64] ] -class _FindPeaksResultsDict(TypedDict): - peak_heights: NotRequired[npt.NDArray[np.float64]] - left_thresholds: NotRequired[npt.NDArray[np.float64]] - right_thresholds: NotRequired[npt.NDArray[np.float64]] - prominences: NotRequired[npt.NDArray[np.float64]] - left_bases: NotRequired[npt.NDArray[np.intp]] - right_bases: NotRequired[npt.NDArray[np.intp]] - width_heights: NotRequired[npt.NDArray[np.float64]] - left_ips: NotRequired[npt.NDArray[np.float64]] - right_ips: NotRequired[npt.NDArray[np.float64]] - plateau_sizes: NotRequired[npt.NDArray[np.intp]] - left_edges: NotRequired[npt.NDArray[np.intp]] - right_edges: NotRequired[npt.NDArray[np.intp]] +class _FindPeaksResultsDict(TypedDict, total=False): + peak_heights: npt.NDArray[np.float64] + left_thresholds: npt.NDArray[np.float64] + right_thresholds: npt.NDArray[np.float64] + prominences: npt.NDArray[np.float64] + left_bases: npt.NDArray[np.intp] + right_bases: npt.NDArray[np.intp] + width_heights: npt.NDArray[np.float64] + left_ips: npt.NDArray[np.float64] + right_ips: npt.NDArray[np.float64] + plateau_sizes: npt.NDArray[np.intp] + left_edges: npt.NDArray[np.intp] + right_edges: npt.NDArray[np.intp] def argrelmin( data: npt.NDArray[np.generic], axis: int = 0, order: int = 1, mode: _Mode = "clip" From b453d066e2f960e2c54dcfbbad7c75f8041b3e16 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Thu, 17 Oct 2024 11:33:40 +1100 Subject: [PATCH 06/21] `signal`: Adjust the function argument list formatting For `_peak_finding.pyi`. --- scipy-stubs/signal/_peak_finding.pyi | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index 1d2cc73f..6ea551ff 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -27,10 +27,16 @@ class _FindPeaksResultsDict(TypedDict, total=False): right_edges: npt.NDArray[np.intp] def argrelmin( - data: npt.NDArray[np.generic], axis: int = 0, order: int = 1, mode: _Mode = "clip" + data: npt.NDArray[np.generic], + axis: int = 0, + order: int = 1, + mode: _Mode = "clip", ) -> tuple[npt.NDArray[np.intp], ...]: ... def argrelmax( - data: npt.NDArray[np.generic], axis: int = 0, order: int = 1, mode: _Mode = "clip" + data: npt.NDArray[np.generic], + axis: int = 0, + order: int = 1, + mode: _Mode = "clip", ) -> tuple[npt.NDArray[np.intp], ...]: ... def argrelextrema( data: npt.NDArray[np.generic], @@ -39,7 +45,11 @@ def argrelextrema( order: int = 1, mode: _Mode = "clip", ) -> tuple[npt.NDArray[np.intp], ...]: ... -def peak_prominences(x: npt.ArrayLike, peaks: npt.ArrayLike, wlen: int | None = None) -> _ProminencesResult: ... +def peak_prominences( + x: npt.ArrayLike, + peaks: npt.ArrayLike, + wlen: int | None = None, +) -> _ProminencesResult: ... def peak_widths( x: npt.ArrayLike, peaks: npt.ArrayLike, From d88bb485f007d574795ca36380fe32e9079838bd Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Thu, 17 Oct 2024 13:27:58 +1100 Subject: [PATCH 07/21] `signal`: Use type aliases for common NDArray types In `_peak_finding.pyi` --- scipy-stubs/signal/_peak_finding.pyi | 51 +++++++++++++++------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index 6ea551ff..6fc2be1b 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -6,45 +6,48 @@ import numpy.typing as npt __all__ = ["argrelextrema", "argrelmax", "argrelmin", "find_peaks", "find_peaks_cwt", "peak_prominences", "peak_widths"] +_Array_n: TypeAlias = npt.NDArray[np.intp] +_Array_f8: TypeAlias = npt.NDArray[np.float64] _Mode: TypeAlias = Literal["clip", "wrap"] -_ProminencesResult: TypeAlias = tuple[npt.NDArray[np.float64], npt.NDArray[np.intp], npt.NDArray[np.intp]] + +_ProminencesResult: TypeAlias = tuple[_Array_f8, _Array_n, _Array_n] _WidthsResult: TypeAlias = tuple[ - npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64] + _Array_f8, _Array_f8, _Array_f8, _Array_f8 ] class _FindPeaksResultsDict(TypedDict, total=False): - peak_heights: npt.NDArray[np.float64] - left_thresholds: npt.NDArray[np.float64] - right_thresholds: npt.NDArray[np.float64] - prominences: npt.NDArray[np.float64] - left_bases: npt.NDArray[np.intp] - right_bases: npt.NDArray[np.intp] - width_heights: npt.NDArray[np.float64] - left_ips: npt.NDArray[np.float64] - right_ips: npt.NDArray[np.float64] - plateau_sizes: npt.NDArray[np.intp] - left_edges: npt.NDArray[np.intp] - right_edges: npt.NDArray[np.intp] + peak_heights: _Array_f8 + left_thresholds: _Array_f8 + right_thresholds: _Array_f8 + prominences: _Array_f8 + left_bases: _Array_n + right_bases: _Array_n + width_heights: _Array_f8 + left_ips: _Array_f8 + right_ips: _Array_f8 + plateau_sizes: _Array_n + left_edges: _Array_n + right_edges: _Array_n def argrelmin( data: npt.NDArray[np.generic], axis: int = 0, order: int = 1, mode: _Mode = "clip", -) -> tuple[npt.NDArray[np.intp], ...]: ... +) -> tuple[_Array_n, ...]: ... def argrelmax( data: npt.NDArray[np.generic], axis: int = 0, order: int = 1, mode: _Mode = "clip", -) -> tuple[npt.NDArray[np.intp], ...]: ... +) -> tuple[_Array_n, ...]: ... def argrelextrema( data: npt.NDArray[np.generic], comparator: Callable[[npt.NDArray[np.generic], npt.NDArray[np.generic]], npt.NDArray[np.bool_]], axis: int = 0, order: int = 1, mode: _Mode = "clip", -) -> tuple[npt.NDArray[np.intp], ...]: ... +) -> tuple[_Array_n, ...]: ... def peak_prominences( x: npt.ArrayLike, peaks: npt.ArrayLike, @@ -59,19 +62,19 @@ def peak_widths( ) -> _WidthsResult: ... def find_peaks( x: npt.ArrayLike, - height: float | npt.NDArray[np.float64] | tuple[float | None, float | None] | None = None, - threshold: float | npt.NDArray[np.float64] | tuple[float | None, float | None] | None = None, + height: float | _Array_f8 | tuple[float | None, float | None] | None = None, + threshold: float | _Array_f8 | tuple[float | None, float | None] | None = None, distance: np.float64 | None = None, - prominence: float | npt.NDArray[np.float64] | tuple[float | None, float | None] | None = None, - width: float | npt.NDArray[np.float64] | tuple[float | None, float | None] | None = None, + prominence: float | _Array_f8 | tuple[float | None, float | None] | None = None, + width: float | _Array_f8 | tuple[float | None, float | None] | None = None, wlen: int | None = None, rel_height: float = 0.5, - plateau_size: int | npt.NDArray[np.intp] | tuple[int | None, int | None] | None = None, -) -> tuple[npt.NDArray[np.intp], _FindPeaksResultsDict]: ... + plateau_size: int | _Array_n | tuple[int | None, int | None] | None = None, +) -> tuple[_Array_n, _FindPeaksResultsDict]: ... def find_peaks_cwt( vector: npt.ArrayLike, widths: npt.ArrayLike, - wavelet: Callable[Concatenate[int, float, ...], npt.NDArray[np.float64]] | None = None, + wavelet: Callable[Concatenate[int, float, ...], _Array_f8] | None = None, max_distances: Sequence[int] | None = None, gap_thresh: float | None = None, min_length: int | None = None, From 13d8de6540226b961c5fd4f73a39ffa304c284d2 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Thu, 17 Oct 2024 13:34:01 +1100 Subject: [PATCH 08/21] `signal`: Use `_ArrayLikeInt_co` for `peaks` In `_peak_finding.pyi`. --- scipy-stubs/signal/_peak_finding.pyi | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index 6fc2be1b..fbef1a76 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -3,6 +3,7 @@ from typing import Concatenate, Literal, TypeAlias, TypedDict import numpy as np import numpy.typing as npt +from numpy._typing import _ArrayLikeInt_co __all__ = ["argrelextrema", "argrelmax", "argrelmin", "find_peaks", "find_peaks_cwt", "peak_prominences", "peak_widths"] @@ -11,9 +12,7 @@ _Array_f8: TypeAlias = npt.NDArray[np.float64] _Mode: TypeAlias = Literal["clip", "wrap"] _ProminencesResult: TypeAlias = tuple[_Array_f8, _Array_n, _Array_n] -_WidthsResult: TypeAlias = tuple[ - _Array_f8, _Array_f8, _Array_f8, _Array_f8 -] +_WidthsResult: TypeAlias = tuple[_Array_f8, _Array_f8, _Array_f8, _Array_f8] class _FindPeaksResultsDict(TypedDict, total=False): peak_heights: _Array_f8 @@ -50,12 +49,12 @@ def argrelextrema( ) -> tuple[_Array_n, ...]: ... def peak_prominences( x: npt.ArrayLike, - peaks: npt.ArrayLike, + peaks: _ArrayLikeInt_co, wlen: int | None = None, ) -> _ProminencesResult: ... def peak_widths( x: npt.ArrayLike, - peaks: npt.ArrayLike, + peaks: _ArrayLikeInt_co, rel_height: float = 0.5, prominence_data: _ProminencesResult | None = None, wlen: int | None = None, From 73711bcb15ca9b107adc00a80ee9d0055c92ca46 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Thu, 17 Oct 2024 13:35:26 +1100 Subject: [PATCH 09/21] `signal`: Use `op.CanIndex` instead `int` for axis In `_peak_finding.pyi`. --- scipy-stubs/signal/_peak_finding.pyi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index fbef1a76..f859ab2d 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -3,6 +3,7 @@ from typing import Concatenate, Literal, TypeAlias, TypedDict import numpy as np import numpy.typing as npt +import optype as op from numpy._typing import _ArrayLikeInt_co __all__ = ["argrelextrema", "argrelmax", "argrelmin", "find_peaks", "find_peaks_cwt", "peak_prominences", "peak_widths"] @@ -30,20 +31,20 @@ class _FindPeaksResultsDict(TypedDict, total=False): def argrelmin( data: npt.NDArray[np.generic], - axis: int = 0, + axis: op.CanIndex = 0, order: int = 1, mode: _Mode = "clip", ) -> tuple[_Array_n, ...]: ... def argrelmax( data: npt.NDArray[np.generic], - axis: int = 0, + axis: op.CanIndex = 0, order: int = 1, mode: _Mode = "clip", ) -> tuple[_Array_n, ...]: ... def argrelextrema( data: npt.NDArray[np.generic], comparator: Callable[[npt.NDArray[np.generic], npt.NDArray[np.generic]], npt.NDArray[np.bool_]], - axis: int = 0, + axis: op.CanIndex = 0, order: int = 1, mode: _Mode = "clip", ) -> tuple[_Array_n, ...]: ... From 77c60174bd23ecc621518e1ca435a40f6147b497 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Thu, 17 Oct 2024 13:49:52 +1100 Subject: [PATCH 10/21] `signal`: Use `scipy._typing`'s `AnyReal and `AnyInt` In `_peak_finding.pyi` use them instead of `float` and `int` respectively. This is to allow usage of numpy scalars like `float16` and `int32`. --- scipy-stubs/signal/_peak_finding.pyi | 33 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index f859ab2d..cdcb13ac 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -5,6 +5,7 @@ import numpy as np import numpy.typing as npt import optype as op from numpy._typing import _ArrayLikeInt_co +from scipy._typing import AnyInt, AnyReal __all__ = ["argrelextrema", "argrelmax", "argrelmin", "find_peaks", "find_peaks_cwt", "peak_prominences", "peak_widths"] @@ -51,34 +52,34 @@ def argrelextrema( def peak_prominences( x: npt.ArrayLike, peaks: _ArrayLikeInt_co, - wlen: int | None = None, + wlen: AnyReal | None = None, ) -> _ProminencesResult: ... def peak_widths( x: npt.ArrayLike, peaks: _ArrayLikeInt_co, - rel_height: float = 0.5, + rel_height: AnyReal = 0.5, prominence_data: _ProminencesResult | None = None, - wlen: int | None = None, + wlen: AnyReal | None = None, ) -> _WidthsResult: ... def find_peaks( x: npt.ArrayLike, - height: float | _Array_f8 | tuple[float | None, float | None] | None = None, - threshold: float | _Array_f8 | tuple[float | None, float | None] | None = None, - distance: np.float64 | None = None, - prominence: float | _Array_f8 | tuple[float | None, float | None] | None = None, - width: float | _Array_f8 | tuple[float | None, float | None] | None = None, - wlen: int | None = None, - rel_height: float = 0.5, - plateau_size: int | _Array_n | tuple[int | None, int | None] | None = None, + height: AnyReal | _Array_f8 | tuple[AnyReal | None, AnyReal | None] | None = None, + threshold: AnyReal | _Array_f8 | tuple[AnyReal | None, AnyReal | None] | None = None, + distance: AnyReal | None = None, + prominence: AnyReal | _Array_f8 | tuple[AnyReal | None, AnyReal | None] | None = None, + width: AnyReal | _Array_f8 | tuple[AnyReal | None, AnyReal | None] | None = None, + wlen: AnyReal | None = None, + rel_height: AnyReal = 0.5, + plateau_size: AnyInt | _Array_n | tuple[AnyInt | None, AnyInt | None] | None = None, ) -> tuple[_Array_n, _FindPeaksResultsDict]: ... def find_peaks_cwt( vector: npt.ArrayLike, widths: npt.ArrayLike, wavelet: Callable[Concatenate[int, float, ...], _Array_f8] | None = None, max_distances: Sequence[int] | None = None, - gap_thresh: float | None = None, - min_length: int | None = None, - min_snr: int = 1, - noise_perc: int = 10, - window_size: int | None = None, + gap_thresh: AnyInt | None = None, + min_length: AnyInt | None = None, + min_snr: AnyReal = 1, + noise_perc: AnyReal = 10, + window_size: AnyInt | None = None, ) -> npt.NDArray[np.intp]: ... From cfbae52561212599fc2c6b2e1ba1381e3cd64219 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Thu, 17 Oct 2024 13:52:51 +1100 Subject: [PATCH 11/21] `signal`: Specify that a 1D array is returned for `find_peaks_cwt` --- scipy-stubs/signal/_peak_finding.pyi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index cdcb13ac..b7d97835 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -10,6 +10,7 @@ from scipy._typing import AnyInt, AnyReal __all__ = ["argrelextrema", "argrelmax", "argrelmin", "find_peaks", "find_peaks_cwt", "peak_prominences", "peak_widths"] _Array_n: TypeAlias = npt.NDArray[np.intp] +_Array_n_1d: TypeAlias = np.ndarray[tuple[int], np.dtype[np.intp]] _Array_f8: TypeAlias = npt.NDArray[np.float64] _Mode: TypeAlias = Literal["clip", "wrap"] @@ -82,4 +83,4 @@ def find_peaks_cwt( min_snr: AnyReal = 1, noise_perc: AnyReal = 10, window_size: AnyInt | None = None, -) -> npt.NDArray[np.intp]: ... +) -> _Array_n_1d: ... From 2266ca03088f55b755e902f7f593a68b278189f5 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Thu, 17 Oct 2024 13:58:12 +1100 Subject: [PATCH 12/21] `signal`: Loosen type constraint on `wavelet` In `_peak_finding.pyi`. The `wavelet` parameter does not need to return `NDArray[np.float64]` it only needs to return something that can be coerced into a numpy array. --- scipy-stubs/signal/_peak_finding.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index b7d97835..c0fa6f6a 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -76,7 +76,7 @@ def find_peaks( def find_peaks_cwt( vector: npt.ArrayLike, widths: npt.ArrayLike, - wavelet: Callable[Concatenate[int, float, ...], _Array_f8] | None = None, + wavelet: Callable[Concatenate[int, float, ...], npt.ArrayLike] | None = None, max_distances: Sequence[int] | None = None, gap_thresh: AnyInt | None = None, min_length: AnyInt | None = None, From beda31b33d09408656f6974fd0b9a33da9b72bec Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Thu, 17 Oct 2024 20:25:53 +1100 Subject: [PATCH 13/21] `signal`: Use ArrayLike type aliases from numpy instead of NDArrays In `_peak_finding.pyi`'s `find_peaks` instead of having separate type annotations for scalars and NDArrays that have a concrete dtype, use numpy's _ArrayLike*_co type aliases to cover both cases and allow for various dtypese --- scipy-stubs/signal/_peak_finding.pyi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index c0fa6f6a..48805b74 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -4,7 +4,7 @@ from typing import Concatenate, Literal, TypeAlias, TypedDict import numpy as np import numpy.typing as npt import optype as op -from numpy._typing import _ArrayLikeInt_co +from numpy._typing import _ArrayLikeFloat_co, _ArrayLikeInt_co from scipy._typing import AnyInt, AnyReal __all__ = ["argrelextrema", "argrelmax", "argrelmin", "find_peaks", "find_peaks_cwt", "peak_prominences", "peak_widths"] @@ -64,14 +64,14 @@ def peak_widths( ) -> _WidthsResult: ... def find_peaks( x: npt.ArrayLike, - height: AnyReal | _Array_f8 | tuple[AnyReal | None, AnyReal | None] | None = None, - threshold: AnyReal | _Array_f8 | tuple[AnyReal | None, AnyReal | None] | None = None, + height: _ArrayLikeFloat_co | tuple[AnyReal | None, AnyReal | None] | None = None, + threshold: _ArrayLikeFloat_co | tuple[AnyReal | None, AnyReal | None] | None = None, distance: AnyReal | None = None, - prominence: AnyReal | _Array_f8 | tuple[AnyReal | None, AnyReal | None] | None = None, - width: AnyReal | _Array_f8 | tuple[AnyReal | None, AnyReal | None] | None = None, + prominence: _ArrayLikeFloat_co | tuple[AnyReal | None, AnyReal | None] | None = None, + width: _ArrayLikeFloat_co | tuple[AnyReal | None, AnyReal | None] | None = None, wlen: AnyReal | None = None, rel_height: AnyReal = 0.5, - plateau_size: AnyInt | _Array_n | tuple[AnyInt | None, AnyInt | None] | None = None, + plateau_size: _ArrayLikeInt_co | tuple[AnyInt | None, AnyInt | None] | None = None, ) -> tuple[_Array_n, _FindPeaksResultsDict]: ... def find_peaks_cwt( vector: npt.ArrayLike, From 85f19ce692271c622b13047329e58bd0b7d41eda Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Sat, 19 Oct 2024 15:34:34 +1100 Subject: [PATCH 14/21] `signal`: Adjust type annotations for `find_peaks_cwt` In `_peak_finding.pyi` --- scipy-stubs/signal/_peak_finding.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index 48805b74..ca934c04 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -77,8 +77,8 @@ def find_peaks_cwt( vector: npt.ArrayLike, widths: npt.ArrayLike, wavelet: Callable[Concatenate[int, float, ...], npt.ArrayLike] | None = None, - max_distances: Sequence[int] | None = None, - gap_thresh: AnyInt | None = None, + max_distances: _ArrayLikeInt_co | None = None, + gap_thresh: AnyReal | None = None, min_length: AnyInt | None = None, min_snr: AnyReal = 1, noise_perc: AnyReal = 10, From 17930b7bda7e018a3de4754a7a4adb3ff09cc9cb Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Sat, 19 Oct 2024 15:35:35 +1100 Subject: [PATCH 15/21] `signal`: Use `AnyInt` for `order` arguments In `_peak_finding.pyi`. --- scipy-stubs/signal/_peak_finding.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index ca934c04..05b3e655 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -34,20 +34,20 @@ class _FindPeaksResultsDict(TypedDict, total=False): def argrelmin( data: npt.NDArray[np.generic], axis: op.CanIndex = 0, - order: int = 1, + order: AnyInt = 1, mode: _Mode = "clip", ) -> tuple[_Array_n, ...]: ... def argrelmax( data: npt.NDArray[np.generic], axis: op.CanIndex = 0, - order: int = 1, + order: AnyInt = 1, mode: _Mode = "clip", ) -> tuple[_Array_n, ...]: ... def argrelextrema( data: npt.NDArray[np.generic], comparator: Callable[[npt.NDArray[np.generic], npt.NDArray[np.generic]], npt.NDArray[np.bool_]], axis: op.CanIndex = 0, - order: int = 1, + order: AnyInt = 1, mode: _Mode = "clip", ) -> tuple[_Array_n, ...]: ... def peak_prominences( From d7b9cbd82662e3e907df08d3c014658adeb43a5f Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Sat, 19 Oct 2024 16:22:20 +1100 Subject: [PATCH 16/21] `signal`: Adjust type annotation for `wavelet` argument For the function `find_peaks_cwt` in `_peak_finding.pyi`. --- scipy-stubs/signal/_peak_finding.pyi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index 05b3e655..5b19c65b 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -16,6 +16,7 @@ _Mode: TypeAlias = Literal["clip", "wrap"] _ProminencesResult: TypeAlias = tuple[_Array_f8, _Array_n, _Array_n] _WidthsResult: TypeAlias = tuple[_Array_f8, _Array_f8, _Array_f8, _Array_f8] +_WaveletFunction: TypeAlias = Callable[Concatenate[int | np.int_ | np.float64, AnyReal, ...], npt.NDArray[np.generic]] class _FindPeaksResultsDict(TypedDict, total=False): peak_heights: _Array_f8 @@ -76,7 +77,7 @@ def find_peaks( def find_peaks_cwt( vector: npt.ArrayLike, widths: npt.ArrayLike, - wavelet: Callable[Concatenate[int, float, ...], npt.ArrayLike] | None = None, + wavelet: _WaveletFunction | None = None, max_distances: _ArrayLikeInt_co | None = None, gap_thresh: AnyReal | None = None, min_length: AnyInt | None = None, From 5e1d325fa8e42fcc09e3fd6c7604afd5f1aa5650 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Sat, 19 Oct 2024 16:29:18 +1100 Subject: [PATCH 17/21] `signal`: Remove unused import in `_peak_finding.pyi`. --- scipy-stubs/signal/_peak_finding.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index 5b19c65b..15f25faa 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -1,4 +1,4 @@ -from collections.abc import Callable, Sequence +from collections.abc import Callable from typing import Concatenate, Literal, TypeAlias, TypedDict import numpy as np From 28fad98c27a1efa4e8fc9f973586070decbba4b3 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Sat, 19 Oct 2024 17:07:10 +1100 Subject: [PATCH 18/21] `signal`: Use a bounded `TypeVar` for the comparator function argument For the `argrelextrema` function in `_peak_finding.pyi`. --- scipy-stubs/signal/_peak_finding.pyi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index 15f25faa..55671784 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -1,5 +1,5 @@ from collections.abc import Callable -from typing import Concatenate, Literal, TypeAlias, TypedDict +from typing import Concatenate, Literal, TypeAlias, TypedDict, TypeVar import numpy as np import numpy.typing as npt @@ -9,6 +9,8 @@ from scipy._typing import AnyInt, AnyReal __all__ = ["argrelextrema", "argrelmax", "argrelmin", "find_peaks", "find_peaks_cwt", "peak_prominences", "peak_widths"] +_SCT = TypeVar("_SCT", bound=np.generic) + _Array_n: TypeAlias = npt.NDArray[np.intp] _Array_n_1d: TypeAlias = np.ndarray[tuple[int], np.dtype[np.intp]] _Array_f8: TypeAlias = npt.NDArray[np.float64] @@ -46,7 +48,7 @@ def argrelmax( ) -> tuple[_Array_n, ...]: ... def argrelextrema( data: npt.NDArray[np.generic], - comparator: Callable[[npt.NDArray[np.generic], npt.NDArray[np.generic]], npt.NDArray[np.bool_]], + comparator: Callable[[npt.NDArray[_SCT], npt.NDArray[_SCT]], npt.NDArray[np.bool_]], axis: op.CanIndex = 0, order: AnyInt = 1, mode: _Mode = "clip", From 11fa2aaba1050d5f3fbebf680b2fbe3087b7babb Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Sun, 20 Oct 2024 11:30:54 +1100 Subject: [PATCH 19/21] `signal`: Adjust type annotations for `find_peaks_cwt` Found in `_peak_finding.pyi`. Changes are: 1. Use `_ArrayLikeFloat_co` for `widths` parameter This is because the documents specify `float or sequence` so the dtype is implied to be float. 2. Change type annotation for `max_distances` from `_ArrayLikeInt_co` to `_ArrayLikeFloat_co`. In case of `None` the array is given by the `widths` parameter divided by 4.0 so it is has to be compatible with float dtypes. 3. Change the output for `_WaveletFunction` to be more accurate. The output has to be sliceable with the type of the sliced access being an array like. --- scipy-stubs/signal/_peak_finding.pyi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index 55671784..134108ca 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -18,7 +18,8 @@ _Mode: TypeAlias = Literal["clip", "wrap"] _ProminencesResult: TypeAlias = tuple[_Array_f8, _Array_n, _Array_n] _WidthsResult: TypeAlias = tuple[_Array_f8, _Array_f8, _Array_f8, _Array_f8] -_WaveletFunction: TypeAlias = Callable[Concatenate[int | np.int_ | np.float64, AnyReal, ...], npt.NDArray[np.generic]] +_WaveletOutput: TypeAlias = op.CanGetitem[slice, npt.ArrayLike] +_WaveletFunction: TypeAlias = Callable[Concatenate[int | np.int_ | np.float64, AnyReal, ...], _WaveletOutput] class _FindPeaksResultsDict(TypedDict, total=False): peak_heights: _Array_f8 @@ -78,9 +79,9 @@ def find_peaks( ) -> tuple[_Array_n, _FindPeaksResultsDict]: ... def find_peaks_cwt( vector: npt.ArrayLike, - widths: npt.ArrayLike, + widths: _ArrayLikeFloat_co, wavelet: _WaveletFunction | None = None, - max_distances: _ArrayLikeInt_co | None = None, + max_distances: _ArrayLikeFloat_co | None = None, gap_thresh: AnyReal | None = None, min_length: AnyInt | None = None, min_snr: AnyReal = 1, From bb24cada747dcda911039b632de37066e28e9751 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Sun, 20 Oct 2024 11:49:39 +1100 Subject: [PATCH 20/21] `signal`: Change type annotation for `find_peaks_cwt` Found in `_peak_finding.pyi`. Change the type annotation for the `vector` parameter from `ArrayLike` to `NDArray[generic]`. The docs specify the input as `ndarray` not an array like and as there is no conversion in the source code, we can't use `ArrayLike`. --- scipy-stubs/signal/_peak_finding.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index 134108ca..b6fd98f1 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -78,7 +78,7 @@ def find_peaks( plateau_size: _ArrayLikeInt_co | tuple[AnyInt | None, AnyInt | None] | None = None, ) -> tuple[_Array_n, _FindPeaksResultsDict]: ... def find_peaks_cwt( - vector: npt.ArrayLike, + vector: npt.NDArray[np.generic], widths: _ArrayLikeFloat_co, wavelet: _WaveletFunction | None = None, max_distances: _ArrayLikeFloat_co | None = None, From 9f1ca741859a947b7d119ef5912ecef3a0383bd4 Mon Sep 17 00:00:00 2001 From: Pavadol Yamsiri Date: Sun, 20 Oct 2024 15:38:17 +1100 Subject: [PATCH 21/21] `signal`: Make `max_distances` an NDArray In `_peak_finding.pyi` and the function `find_peaks_cwt`. According to docs this is an NDArray not an ArrayLike. --- scipy-stubs/signal/_peak_finding.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scipy-stubs/signal/_peak_finding.pyi b/scipy-stubs/signal/_peak_finding.pyi index b6fd98f1..94cbb74e 100644 --- a/scipy-stubs/signal/_peak_finding.pyi +++ b/scipy-stubs/signal/_peak_finding.pyi @@ -1,5 +1,5 @@ from collections.abc import Callable -from typing import Concatenate, Literal, TypeAlias, TypedDict, TypeVar +from typing import Any, Concatenate, Literal, TypeAlias, TypedDict, TypeVar import numpy as np import numpy.typing as npt @@ -81,7 +81,7 @@ def find_peaks_cwt( vector: npt.NDArray[np.generic], widths: _ArrayLikeFloat_co, wavelet: _WaveletFunction | None = None, - max_distances: _ArrayLikeFloat_co | None = None, + max_distances: npt.NDArray[np.floating[Any] | np.integer[Any]] | None = None, gap_thresh: AnyReal | None = None, min_length: AnyInt | None = None, min_snr: AnyReal = 1,