diff --git a/src/machinevisiontoolbox/BundleAdjust.py b/src/machinevisiontoolbox/BundleAdjust.py index e6a8cd0d..d822dcae 100644 --- a/src/machinevisiontoolbox/BundleAdjust.py +++ b/src/machinevisiontoolbox/BundleAdjust.py @@ -12,7 +12,7 @@ import pgraph pgraph_installed = True -except: +except ImportError: print("pgraph not installed") pgraph_installed = False import matplotlib.pyplot as plt diff --git a/src/machinevisiontoolbox/Camera.py b/src/machinevisiontoolbox/Camera.py index 55ae67e9..3e557784 100644 --- a/src/machinevisiontoolbox/Camera.py +++ b/src/machinevisiontoolbox/Camera.py @@ -827,7 +827,7 @@ def clf(self) -> None: for artist in self._ax.get_children(): try: artist.remove() - except: + except Exception: pass def plot_point( @@ -1862,7 +1862,7 @@ def fov(self) -> np.ndarray: """ try: return 2 * np.arctan(np.r_[self.imagesize] / 2 * np.r_[self.rho] / self.f) - except: + except (TypeError, AttributeError): raise ValueError("imagesize or rho properties not set") def distort(self, points: np.ndarray) -> np.ndarray: diff --git a/src/machinevisiontoolbox/ImagePointFeatures.py b/src/machinevisiontoolbox/ImagePointFeatures.py index d3db6020..dd4cbac4 100644 --- a/src/machinevisiontoolbox/ImagePointFeatures.py +++ b/src/machinevisiontoolbox/ImagePointFeatures.py @@ -282,7 +282,7 @@ def gridify(self, nbins: int | tuple[int, int], nfeat: int) -> "BaseFeature2D": try: # Sort features into grid nw, nh = nbins - except: + except (TypeError, ValueError): nw = nbins nh = nbins diff --git a/src/machinevisiontoolbox/ImageProcessing.py b/src/machinevisiontoolbox/ImageProcessing.py index 164a00c1..1b33b44e 100644 --- a/src/machinevisiontoolbox/ImageProcessing.py +++ b/src/machinevisiontoolbox/ImageProcessing.py @@ -1146,7 +1146,7 @@ def choose(self, image2: Any, mask: Any) -> "Image": else: try: color = argcheck.getvector(image2, 3) - except: + except Exception: raise ValueError("expecting a scalar, string or 3-vector") if self.isbgr: color = color[::-1] diff --git a/src/machinevisiontoolbox/__init__.py b/src/machinevisiontoolbox/__init__.py index d59296ee..21f6c37c 100644 --- a/src/machinevisiontoolbox/__init__.py +++ b/src/machinevisiontoolbox/__init__.py @@ -188,5 +188,5 @@ import importlib.metadata __version__ = importlib.metadata.version("machinevision-toolbox-python") -except: +except importlib.metadata.PackageNotFoundError: pass diff --git a/tech-debt.md b/tech-debt.md index 93975529..d618f8b4 100644 --- a/tech-debt.md +++ b/tech-debt.md @@ -1,5 +1,39 @@ # Technical Debt +## `BaseFeature2D.gridify()` crashes with IndexError, always + +Found 2026-07-29 while verifying the narrowed exception type on +`ImagePointFeatures.py:283`'s `nw, nh = nbins` unpack (part of a bare +`except:` cleanup). `gridify()` (`ImagePointFeatures.py:261-301`) +raises `IndexError: arrays used as indices must be of integer (or +boolean) type` on every call, regardless of whether `nbins` is passed +as a tuple or a scalar int — confirmed via `git stash` that this is +identical on unmodified `main`, unrelated to the except-type change +that surfaced it. + +Root cause: `ix = f.p[0] // binwidth` / `iy = f.p[1] // binheight` +(lines 294-295) — `f.p` is a numpy float array (feature point +coordinates), and floor-dividing a numpy float array by a Python int +still yields a numpy `float64` result, not an int. `bins[iy, ix]` +(line 300) then fails because numpy refuses float-dtype indices. + +### Fix + +Cast to int after the floor division, e.g. +`ix = int(f.p[0] // binwidth)` / `iy = int(f.p[1] // binheight)`. Small, +self-contained, real bug fix — bundle with its own `fix:` commit and a +regression test (`gridify()` currently has no test coverage at all; +none of the existing point-feature tests exercise it) rather than +folding into an unrelated change. + +### Resolved 2026-07-29 + +Fixed in #30 (`fix/gridify-index-dtype`): `.item()` before the floor +division, then `int()`. Added regression tests (there were none before) +covering both scalar and tuple `nbins`; verified genuinely by reverting +just the source fix and confirming the tests fail with the exact +reported `IndexError` before restoring it. + ## [HIGH PRIORITY] mypy is not run anywhere in CI or dev tooling Found 2026-07-29 while fixing the `_ImageBase` Protocol gaps in