From 193734f8de027da2b834d9aaade9dfd97f7145c5 Mon Sep 17 00:00:00 2001 From: Pringled Date: Sat, 4 Oct 2025 14:56:29 +0200 Subject: [PATCH 1/4] Added informative import errors --- README.md | 2 +- vicinity/backends/__init__.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a4c21f2..61c7e41 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@

Package version - Supported Python versions + Docs Downloads diff --git a/vicinity/backends/__init__.py b/vicinity/backends/__init__.py index 28782a9..4dc1b5b 100644 --- a/vicinity/backends/__init__.py +++ b/vicinity/backends/__init__.py @@ -1,3 +1,4 @@ +from importlib.util import find_spec from typing import Union from vicinity.backends.base import AbstractBackend @@ -5,35 +6,56 @@ from vicinity.datatypes import Backend +class OptionalDependencyError(ImportError): + def __init__(self, backend: Backend, extra: str) -> None: + msg = f"{backend} requires extra '{extra}'.\n" f"Install it with: `pip install vicinity[{extra}]`\n" + super().__init__(msg) + self.backend = backend + self.extra = extra + + +def _require(module_name: str, backend: Backend, extra: str) -> None: + """Check if a dependency is importable, otherwise raise an error.""" + if find_spec(module_name) is None: + raise OptionalDependencyError(backend, extra) + + def get_backend_class(backend: Union[Backend, str]) -> type[AbstractBackend]: """Get all available backends.""" backend = Backend(backend) if backend == Backend.BASIC: return BasicBackend + elif backend == Backend.HNSW: + _require("hnswlib", backend, "hnswlib") from vicinity.backends.hnsw import HNSWBackend return HNSWBackend elif backend == Backend.ANNOY: + _require("annoy", backend, "annoy") from vicinity.backends.annoy import AnnoyBackend return AnnoyBackend elif backend == Backend.PYNNDESCENT: + _require("pynndescent", backend, "pynndescent") from vicinity.backends.pynndescent import PyNNDescentBackend return PyNNDescentBackend elif backend == Backend.FAISS: + _require("faiss", backend, "faiss-cpu or faiss-gpu") from vicinity.backends.faiss import FaissBackend return FaissBackend elif backend == Backend.USEARCH: + _require("usearch", backend, "usearch") from vicinity.backends.usearch import UsearchBackend return UsearchBackend elif backend == Backend.VOYAGER: + _require("voyager", backend, "voyager") from vicinity.backends.voyager import VoyagerBackend return VoyagerBackend From bc7169c94b11ef3c79e763a095d7fa348a359d9d Mon Sep 17 00:00:00 2001 From: Pringled Date: Sat, 4 Oct 2025 14:58:24 +0200 Subject: [PATCH 2/4] Added informative import errors --- vicinity/backends/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vicinity/backends/__init__.py b/vicinity/backends/__init__.py index 4dc1b5b..5c37f60 100644 --- a/vicinity/backends/__init__.py +++ b/vicinity/backends/__init__.py @@ -21,8 +21,9 @@ def _require(module_name: str, backend: Backend, extra: str) -> None: def get_backend_class(backend: Union[Backend, str]) -> type[AbstractBackend]: - """Get all available backends.""" + """Get the requested backend and ensure its dependencies are installed.""" backend = Backend(backend) + if backend == Backend.BASIC: return BasicBackend @@ -31,11 +32,13 @@ def get_backend_class(backend: Union[Backend, str]) -> type[AbstractBackend]: from vicinity.backends.hnsw import HNSWBackend return HNSWBackend + elif backend == Backend.ANNOY: _require("annoy", backend, "annoy") from vicinity.backends.annoy import AnnoyBackend return AnnoyBackend + elif backend == Backend.PYNNDESCENT: _require("pynndescent", backend, "pynndescent") from vicinity.backends.pynndescent import PyNNDescentBackend From ad46bdaed0136ce699a87adc1b7fd18048f8aaf6 Mon Sep 17 00:00:00 2001 From: Pringled Date: Sat, 4 Oct 2025 15:01:59 +0200 Subject: [PATCH 3/4] Bumped version --- vicinity/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vicinity/version.py b/vicinity/version.py index 29d357c..56a9515 100644 --- a/vicinity/version.py +++ b/vicinity/version.py @@ -1,2 +1,2 @@ -__version_triple__ = (0, 4, 2) +__version_triple__ = (0, 4, 3) __version__ = ".".join(map(str, __version_triple__)) From 20e3d7dbf016b8a53a5af9b4a69314c00eeff0e2 Mon Sep 17 00:00:00 2001 From: Pringled Date: Sat, 4 Oct 2025 15:16:09 +0200 Subject: [PATCH 4/4] Added informative import errors --- vicinity/backends/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vicinity/backends/__init__.py b/vicinity/backends/__init__.py index 5c37f60..e615edf 100644 --- a/vicinity/backends/__init__.py +++ b/vicinity/backends/__init__.py @@ -8,7 +8,7 @@ class OptionalDependencyError(ImportError): def __init__(self, backend: Backend, extra: str) -> None: - msg = f"{backend} requires extra '{extra}'.\n" f"Install it with: `pip install vicinity[{extra}]`\n" + msg = f"{backend} requires extra '{extra}'.\n" f"Install it with: pip install 'vicinity[{extra}]'\n" super().__init__(msg) self.backend = backend self.extra = extra @@ -28,7 +28,7 @@ def get_backend_class(backend: Union[Backend, str]) -> type[AbstractBackend]: return BasicBackend elif backend == Backend.HNSW: - _require("hnswlib", backend, "hnswlib") + _require("hnswlib", backend, "hnsw") from vicinity.backends.hnsw import HNSWBackend return HNSWBackend @@ -46,7 +46,7 @@ def get_backend_class(backend: Union[Backend, str]) -> type[AbstractBackend]: return PyNNDescentBackend elif backend == Backend.FAISS: - _require("faiss", backend, "faiss-cpu or faiss-gpu") + _require("faiss", backend, "faiss") from vicinity.backends.faiss import FaissBackend return FaissBackend