diff --git a/rtree/finder.py b/rtree/finder.py index 0c9c67ed..9b7b6355 100644 --- a/rtree/finder.py +++ b/rtree/finder.py @@ -86,6 +86,14 @@ def load() -> ctypes.CDLL: except importlib.metadata.PackageNotFoundError: pass + # Fallback: search relative to package directory + # (works when importlib.metadata is unavailable, e.g. Bazel, some venvs) + libs_dir = _cwd.parent / "rtree.libs" + if libs_dir.exists(): + for so_file in libs_dir.glob("libspatialindex*.so"): + _candidates.insert(1, so_file) + break + for cand in _candidates: if cand.is_dir(): # if our candidate is a directory use best guess diff --git a/tests/test_finder.py b/tests/test_finder.py index 4a05ad2f..230f05be 100644 --- a/tests/test_finder.py +++ b/tests/test_finder.py @@ -1,5 +1,6 @@ from ctypes import CDLL from pathlib import Path +from unittest import mock from rtree import finder @@ -9,6 +10,22 @@ def test_load(): assert isinstance(lib, CDLL) +def test_load_without_importlib_metadata(): + """Test that library loading works when importlib.metadata.files() is unavailable. + + This can happen in sandboxed environments like Bazel where package metadata + isn't properly exposed. + """ + # Reload finder module with mocked importlib.metadata.files returning None + with mock.patch("importlib.metadata.files", return_value=None): + # Need to reload the module to re-run the load logic + import importlib + + importlib.reload(finder) + lib = finder.load() + assert isinstance(lib, CDLL) + + def test_get_include(): incl = finder.get_include() assert isinstance(incl, str)