Skip to content

Commit defa62a

Browse files
Fix numpy version and remove scipy optional (#347)
Original goal of the task was to relax the forced `numpy` version constraint that was causing issues in Python 3.11 environments where numpy 2.x.x was required (like Google Colab) ![Screenshot 2025-06-03 at 1 58 50 PM](https://github.com/user-attachments/assets/d1f1bfca-6a81-4cad-8669-e379fca4ba75) ## Problem However, I quickly ran into dependency chain issues with: - `scipy` -- the scientific computing stack is a bit like a dinosaur still - `boto3` -- always an issue - `ranx` -- not really sure why, but this one has 13+ separate dependencies and includes a pin on `numba` that expects certain things from `numpy` and then it gets easily circular ## Solution: Working together with claude, I was able to resolve and rebuild the environment and the lockfile with one major change. - `ranx` is still an optional, but it's not an explicit extra. - What does that mean? Literally only means that if devs are using `ranx` they have to install it with `pip install ranx` instead of `pip install redisvl[ranx]` This could be some kind of limitation with the poetry version I was using. But I spent 6 hours on this with Claude and probably spent 50$ in credits on working through an onion of python environment. It now works and our issues on google colab are gone. I also think the package ranges are a bit more generous now.
1 parent 199d3c0 commit defa62a

File tree

8 files changed

+3639
-3218
lines changed

8 files changed

+3639
-3218
lines changed

.github/workflows/test.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ jobs:
5252
- name: Install dependencies
5353
run: |
5454
poetry install --all-extras
55+
poetry run pip install ranx
5556
5657
- name: Authenticate to Google Cloud
5758
uses: google-github-actions/auth@v1
@@ -116,19 +117,19 @@ jobs:
116117
- name: Install dependencies
117118
run: |
118119
poetry install --all-extras
120+
poetry run pip install ranx
119121
120-
- name: Install specific redis-py version
121-
run: |
122+
# Install right redis version based on redis py
122123
if [[ "${{ matrix.redis-py-version }}" == "5.x" ]]; then
123124
poetry add "redis>=5.0.0,<6.0.0"
124125
else
125126
poetry add "redis>=6.0.0,<7.0.0"
126127
fi
127128
128-
- name: Install hiredis if needed
129-
if: matrix.connection == 'hiredis'
130-
run: |
131-
poetry add hiredis
129+
# Install hiredis if selected
130+
if [[ "${{ matrix.connection }}" == "hiredis" ]]; then
131+
poetry add hiredis
132+
fi
132133
133134
- name: Set Redis image name
134135
run: |
@@ -179,7 +180,7 @@ jobs:
179180
if [[ "${{ matrix.python-version }}" > "3.9" ]]; then
180181
make test-notebooks
181182
else
182-
poetry run test-notebooks --ignore ./docs/user_guide/09_threshold_optimization.ipynb --ignore ./docs/user_guide/release_guide/0_5_0_release.ipynb
183+
poetry run test-notebooks --ignore ./docs/user_guide/09_threshold_optimization.ipynb --ignore ./docs/user_guide/release_guide/0_5_1_release.ipynb
183184
fi
184185
185186
docs:

poetry.lock

Lines changed: 3573 additions & 3174 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,42 +21,39 @@ packages = [{ include = "redisvl", from = "." }]
2121

2222
[tool.poetry.dependencies]
2323
python = ">=3.9,<3.14"
24-
numpy = [
25-
{ version = "^1", python = "<3.12" },
26-
{ version = ">=1.26.0,<3", python = ">=3.12" },
27-
]
24+
numpy = ">=1.26.0,<3"
2825
pyyaml = ">=5.4,<7.0"
2926
redis = ">=5.0,<7.0"
30-
pydantic = "^2"
27+
pydantic = ">=2,<3"
3128
tenacity = ">=8.2.2"
3229
ml-dtypes = ">=0.4.0,<1.0.0"
33-
python-ulid = "^3.0.0"
30+
python-ulid = ">=3.0.0"
31+
jsonpath-ng = ">=1.5.0"
3432
nltk = { version = "^3.8.1", optional = true }
35-
jsonpath-ng = "^1.5.0"
36-
openai = { version = "^1.13.0", optional = true }
37-
sentence-transformers = { version = "^3.4.0", optional = true }
38-
scipy = [
39-
{ version = "<1.15", python = "<3.10", optional = true },
40-
{ version = "^1.15", python = ">=3.10", optional = true }
41-
]
42-
google-cloud-aiplatform = { version = "^1.26", optional = true }
43-
protobuf = { version = "^5.29.1", optional = true }
33+
openai = { version = ">=1.1.0", optional = true }
34+
google-cloud-aiplatform = { version = ">=1.26,<2.0.0", optional = true }
35+
protobuf = { version = ">=5.28.0,<6.0.0", optional = true }
4436
cohere = { version = ">=4.44", optional = true }
4537
mistralai = { version = ">=1.0.0", optional = true }
4638
voyageai = { version = ">=0.2.2", optional = true }
47-
ranx = { version = "^0.3.0", python=">=3.10", optional = true }
48-
boto3 = {version = "1.36.0", optional = true, extras = ["bedrock"]}
39+
sentence-transformers = { version = "^3.4.0", optional = true }
40+
scipy = [
41+
{ version = ">=1.9.0,<1.14", python = "<3.10", optional = true },
42+
{ version = ">=1.14.0,<1.16", python = ">=3.10", optional = true }
43+
]
44+
boto3 = { version = "^1.36.0", optional = true }
45+
urllib3 = { version = "<2.2.0", optional = true }
46+
ranx = {version = "^0.3.20", optional = true}
4947

5048
[tool.poetry.extras]
49+
mistralai = ["mistralai"]
5150
openai = ["openai"]
52-
sentence-transformers = ["sentence-transformers", "scipy"]
53-
vertexai = ["google_cloud_aiplatform", "protobuf"]
51+
nltk = ["nltk"]
5452
cohere = ["cohere"]
55-
mistralai = ["mistralai"]
5653
voyageai = ["voyageai"]
57-
ranx = ["ranx"]
58-
bedrock = ["boto3"]
59-
nltk = ["nltk"]
54+
sentence-transformers = ["sentence-transformers", "scipy"]
55+
vertexai = ["google-cloud-aiplatform", "protobuf"]
56+
bedrock = ["boto3", "urllib3"]
6057

6158
[tool.poetry.group.dev.dependencies]
6259
black = "^25.1.0"
@@ -66,7 +63,7 @@ pytest = "^8.1.1"
6663
pytest-asyncio = "^0.23.6"
6764
pytest-xdist = {extras = ["psutil"], version = "^3.6.1"}
6865
pre-commit = "^4.1.0"
69-
mypy = "1.9.0"
66+
mypy = "^1.11.0"
7067
nbval = "^0.11.0"
7168
types-pyyaml = "*"
7269
types-pyopenssl = "*"

redisvl/redis/connection.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,9 @@ def sync_to_async_redis(
357357
"RedisCluster is not supported for sync-to-async conversion."
358358
)
359359

360+
# At this point, redis_client is guaranteed to be Redis type
361+
assert isinstance(redis_client, Redis) # Type narrowing for MyPy
362+
360363
# pick the right connection class
361364
connection_class: Type[AsyncAbstractConnection] = (
362365
AsyncSSLConnection

redisvl/utils/optimize/cache.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
from typing import Any, Callable, Dict, List
1+
from typing import TYPE_CHECKING, Any, Callable, Dict, List
22

33
from redisvl.utils.utils import lazy_import
44

5+
if TYPE_CHECKING:
6+
from ranx import Qrels, Run, evaluate
7+
else:
8+
Qrels = lazy_import("ranx.Qrels")
9+
Run = lazy_import("ranx.Run")
10+
evaluate = lazy_import("ranx.evaluate")
11+
512
np = lazy_import("numpy")
6-
from ranx import Qrels, Run, evaluate
713

814
from redisvl.extensions.cache.llm.semantic import SemanticCache
915
from redisvl.query import RangeQuery
@@ -12,7 +18,7 @@
1218
from redisvl.utils.optimize.utils import NULL_RESPONSE_KEY, _format_qrels
1319

1420

15-
def _generate_run_cache(test_data: List[LabeledData], threshold: float) -> Run:
21+
def _generate_run_cache(test_data: List[LabeledData], threshold: float) -> "Run":
1622
"""Format observed data for evaluation with ranx"""
1723
run_dict: Dict[str, Dict[str, int]] = {}
1824

@@ -32,7 +38,7 @@ def _generate_run_cache(test_data: List[LabeledData], threshold: float) -> Run:
3238

3339

3440
def _eval_cache(
35-
test_data: List[LabeledData], threshold: float, qrels: Qrels, metric: str
41+
test_data: List[LabeledData], threshold: float, qrels: "Qrels", metric: str
3642
) -> float:
3743
"""Formats run data and evaluates supported metric"""
3844
run = _generate_run_cache(test_data, threshold)

redisvl/utils/optimize/router.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
import random
2-
from typing import Any, Callable, Dict, List
2+
from typing import TYPE_CHECKING, Any, Callable, Dict, List
33

44
from redisvl.utils.utils import lazy_import
55

6+
if TYPE_CHECKING:
7+
from ranx import Qrels, Run, evaluate
8+
else:
9+
Qrels = lazy_import("ranx.Qrels")
10+
Run = lazy_import("ranx.Run")
11+
evaluate = lazy_import("ranx.evaluate")
12+
613
np = lazy_import("numpy")
7-
from ranx import Qrels, Run, evaluate
814

915
from redisvl.extensions.router.semantic import SemanticRouter
1016
from redisvl.utils.optimize.base import BaseThresholdOptimizer, EvalMetric
1117
from redisvl.utils.optimize.schema import LabeledData
1218
from redisvl.utils.optimize.utils import NULL_RESPONSE_KEY, _format_qrels
1319

1420

15-
def _generate_run_router(test_data: List[LabeledData], router: SemanticRouter) -> Run:
21+
def _generate_run_router(test_data: List[LabeledData], router: SemanticRouter) -> "Run":
1622
"""Format router results into format for ranx Run"""
1723
run_dict: Dict[Any, Any] = {}
1824

@@ -28,7 +34,10 @@ def _generate_run_router(test_data: List[LabeledData], router: SemanticRouter) -
2834

2935

3036
def _eval_router(
31-
router: SemanticRouter, test_data: List[LabeledData], qrels: Qrels, eval_metric: str
37+
router: SemanticRouter,
38+
test_data: List[LabeledData],
39+
qrels: "Qrels",
40+
eval_metric: str,
3241
) -> float:
3342
"""Evaluate acceptable metric given run and qrels data"""
3443
run = _generate_run_router(test_data, router)
@@ -58,7 +67,7 @@ def _router_random_search(
5867
def _random_search_opt_router(
5968
router: SemanticRouter,
6069
test_data: List[LabeledData],
61-
qrels: Qrels,
70+
qrels: "Qrels",
6271
eval_metric: EvalMetric,
6372
**kwargs: Any,
6473
):

redisvl/utils/optimize/utils.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
from typing import List
1+
from typing import TYPE_CHECKING, List
22

33
from redisvl.utils.utils import lazy_import
44

5+
if TYPE_CHECKING:
6+
from ranx import Qrels
7+
else:
8+
Qrels = lazy_import("ranx.Qrels")
9+
510
np = lazy_import("numpy")
6-
from ranx import Qrels
711

812
from redisvl.utils.optimize.schema import LabeledData
913

1014
NULL_RESPONSE_KEY = "no_match"
1115

1216

13-
def _format_qrels(test_data: List[LabeledData]) -> Qrels:
17+
def _format_qrels(test_data: List[LabeledData]) -> "Qrels":
1418
"""Utility function for creating qrels for evaluation with ranx"""
1519
qrels_dict = {}
1620

tests/unit/test_threshold_optimizer_utility.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
if sys.version_info.major == 3 and sys.version_info.minor < 10:
66
pytest.skip("Test requires Python 3.10 or higher", allow_module_level=True)
77

8-
from ranx import evaluate
8+
from redisvl.utils.utils import lazy_import
9+
10+
evaluate = lazy_import("ranx.evaluate")
911

1012
from redisvl.utils.optimize import LabeledData
1113
from redisvl.utils.optimize.cache import _generate_run_cache

0 commit comments

Comments
 (0)