From 4d492d5e00839b56833a76debc0186818ed2eade Mon Sep 17 00:00:00 2001 From: Prajval Arora Date: Tue, 13 Oct 2026 16:34:06 -0700 Subject: [PATCH 1/2] fix: preserve unexpected peak refinement failures --- src/machinevisiontoolbox/base/findpeaks.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/machinevisiontoolbox/base/findpeaks.py b/src/machinevisiontoolbox/base/findpeaks.py index af45314f..fc8a2cb3 100644 --- a/src/machinevisiontoolbox/base/findpeaks.py +++ b/src/machinevisiontoolbox/base/findpeaks.py @@ -4,6 +4,8 @@ from __future__ import annotations +import warnings + import numpy as np import scipy as sp import spatialmath.base as base @@ -116,10 +118,13 @@ def findpeaks( poly, *_ = Polynomial.fit( x[i - n2 : i + n2 + 1], y[i - n2 : i + n2 + 1], interp, full=True ) - except: - # handle situation where neighbourhood falls off the data - # vector - print(f"Peak at {x[i]} couldn't be fitted, skipping") + except (ValueError, np.linalg.LinAlgError): + # A neighbourhood near the boundary can contain too few samples. + warnings.warn( + f"Peak at {x[i]} couldn't be fitted, skipping", + RuntimeWarning, + stacklevel=2, + ) continue # find the roots of the polynomial closest to the coarse peak From c138c25a7af52ab98768c2764d1a34fa6a3819f2 Mon Sep 17 00:00:00 2001 From: Prajval Arora Date: Tue, 13 Oct 2026 16:34:26 -0700 Subject: [PATCH 2/2] test: cover peak fit warnings and error propagation --- tests/base/test_findpeaks.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/base/test_findpeaks.py b/tests/base/test_findpeaks.py index ac2a529b..25e1103d 100644 --- a/tests/base/test_findpeaks.py +++ b/tests/base/test_findpeaks.py @@ -1,6 +1,8 @@ import unittest +from unittest.mock import patch import numpy as np +from numpy.polynomial import Polynomial from machinevisiontoolbox import findpeaks, findpeaks2d, findpeaks3d @@ -8,6 +10,25 @@ class TestFindpeaks(unittest.TestCase): """Test cases for 1D peak finding""" + def test_failed_refinement_warns_and_skips(self): + """Warn when the fit neighbourhood extends beyond the signal.""" + y = np.array([0, 2, 0, 0, 0, 0, 0], dtype=float) + with self.assertWarnsRegex( + RuntimeWarning, "Peak at 1 couldn't be fitted, skipping" + ): + x, ymax = findpeaks(y, interp=6, npeaks=1) + self.assertEqual(x.size, 0) + self.assertEqual(ymax.size, 0) + + def test_refinement_preserves_unexpected_exceptions(self): + """Let unrelated failures and user interrupts reach the caller.""" + y = np.array([0, 1, 2, 1, 0], dtype=float) + for error in (RuntimeError("unexpected failure"), KeyboardInterrupt()): + with self.subTest(error=type(error).__name__): + with patch.object(Polynomial, "fit", side_effect=error): + with self.assertRaises(type(error)): + findpeaks(y, interp=True) + def test_simple_peak(self): """Test detection of simple peak""" y = np.array([0, 0, 1, 2, 0, 0, 0, 3, 1, 0, 0, 0, 0])