Skip to content

Commit 66bac99

Browse files
committed
Removed dependency on NumPy [skip ci]
1 parent 2155f99 commit 66bac99

21 files changed

Lines changed: 154 additions & 47 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- Changed `vector` type to return `Vector` object instead of NumPy array
55
- Removed `utils` package (use top-level `pgvector` package instead)
66
- Removed re-exported classes (use top-level `pgvector` package instead)
7+
- Removed dependency on NumPy
78
- Dropped support for Python < 3.10
89
- Dropped support for SQLAlchemy < 2
910

pgvector/bit.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from __future__ import annotations
2-
import numpy as np
32
from struct import pack, unpack_from
43
from warnings import warn
54

@@ -13,6 +12,8 @@ def __init__(self, value: bytes | str | list[bool] | np.ndarray[tuple[int], np.d
1312
if isinstance(value, str):
1413
value = [v != '0' for v in value]
1514
else:
15+
import numpy as np
16+
1617
value = np.asarray(value)
1718

1819
# for mypy

pgvector/halfvec.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
from __future__ import annotations
2-
import numpy as np
32
import struct
43

4+
try:
5+
import numpy as np
6+
except ImportError:
7+
np = None
8+
59

610
class HalfVector:
711
def __init__(self, value: list[float] | np.ndarray[tuple[int], np.dtype[np.floating]]) -> None:
@@ -11,7 +15,7 @@ def __init__(self, value: list[float] | np.ndarray[tuple[int], np.dtype[np.float
1115
self._value = struct.pack(f'>HH{dim}e', dim, 0, *value)
1216
except struct.error:
1317
raise ValueError('expected list[float]')
14-
elif isinstance(value, np.ndarray):
18+
elif np is not None and isinstance(value, np.ndarray):
1519
if value.ndim != 1:
1620
raise ValueError('expected ndim to be 1')
1721

pgvector/pg8000/register.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
import numpy as np
21
from pg8000.native import Connection
32
from .. import Vector, HalfVector, SparseVector
43

4+
try:
5+
import numpy as np
6+
except ImportError:
7+
np = None
8+
59

610
def register_vector(conn: Connection) -> None:
711
# use to_regtype to get first matching type in search path
@@ -12,7 +16,8 @@ def register_vector(conn: Connection) -> None:
1216
raise RuntimeError('vector type not found in the database')
1317

1418
conn.register_out_adapter(Vector, Vector._to_db)
15-
conn.register_out_adapter(np.ndarray, Vector._to_db)
19+
if np is not None:
20+
conn.register_out_adapter(np.ndarray, Vector._to_db)
1621
conn.register_in_adapter(type_info['vector'], Vector._from_db)
1722

1823
if 'halfvec' in type_info:

pgvector/psycopg/vector.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import numpy as np
21
import psycopg
32
from psycopg import BaseConnection
43
from psycopg.adapt import Loader, Dumper

pgvector/psycopg2/vector.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
import numpy as np
21
from psycopg2.extensions import adapt, connection, cursor, new_array_type, new_type, register_adapter, register_type
32
from .. import Vector
43

4+
try:
5+
import numpy as np
6+
except ImportError:
7+
np = None
8+
59

610
class VectorAdapter:
711
def __init__(self, value: object) -> None:
@@ -23,5 +27,6 @@ def register_vector_info(oid: int, array_oid: int | None, scope: connection | cu
2327
vectorarray = new_array_type((array_oid,), 'VECTORARRAY', vector)
2428
register_type(vectorarray, scope)
2529

26-
register_adapter(np.ndarray, VectorAdapter)
30+
if np is not None:
31+
register_adapter(np.ndarray, VectorAdapter)
2732
register_adapter(Vector, VectorAdapter)

pgvector/sparsevec.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
from __future__ import annotations
2-
import numpy as np
32
from struct import pack, unpack_from
43
from typing import Any, overload
54

5+
try:
6+
import numpy as np
7+
except ImportError:
8+
np = None
9+
610
NO_DEFAULT = object()
711

812

pgvector/vector.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
from __future__ import annotations
2-
import numpy as np
32
import struct
43

4+
try:
5+
import numpy as np
6+
except ImportError:
7+
np = None
8+
59

610
class Vector:
711
def __init__(self, value: list[float] | np.ndarray[tuple[int], np.dtype[np.floating]]) -> None:
@@ -11,7 +15,7 @@ def __init__(self, value: list[float] | np.ndarray[tuple[int], np.dtype[np.float
1115
self._value = struct.pack(f'>HH{dim}f', dim, 0, *value)
1216
except struct.error:
1317
raise ValueError('expected list[float]')
14-
elif isinstance(value, np.ndarray):
18+
elif np is not None and isinstance(value, np.ndarray):
1519
if value.ndim != 1:
1620
raise ValueError('expected ndim to be 1')
1721

pyproject.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ authors = [
1313
license = "MIT"
1414
requires-python = ">= 3.10"
1515
dependencies = [
16-
"numpy"
1716
]
1817

1918
[project.urls]
@@ -29,10 +28,13 @@ dev = [
2928
"psycopg2-binary",
3029
"pytest",
3130
"pytest-asyncio",
32-
"scipy",
3331
"SQLAlchemy[asyncio]>=2",
3432
"sqlmodel>=0.0.12"
3533
]
34+
dev2 = [
35+
"numpy",
36+
"scipy"
37+
]
3638

3739
[tool.pytest.ini_options]
3840
asyncio_mode = "auto"

tests/test_asyncpg.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import asyncpg
2-
import numpy as np
32
from pgvector import HalfVector, SparseVector, Vector
43
from pgvector.asyncpg import register_vector
54
import pytest
@@ -16,7 +15,7 @@ async def test_vector(self):
1615
await register_vector(conn)
1716

1817
embedding = Vector([1.5, 2, 3])
19-
embedding2 = np.array([4.5, 5, 6])
18+
embedding2 = [4.5, 5, 6]
2019
await conn.execute("INSERT INTO asyncpg_items (embedding) VALUES ($1), ($2), (NULL)", embedding, embedding2)
2120

2221
res = await conn.fetch("SELECT * FROM asyncpg_items ORDER BY id")
@@ -111,7 +110,7 @@ async def test_vector_array(self):
111110
embeddings = [Vector([1.5, 2, 3]), Vector([4.5, 5, 6])]
112111
await conn.execute("INSERT INTO asyncpg_items (embeddings) VALUES ($1)", embeddings)
113112

114-
embeddings2 = [np.array([1.5, 2, 3]), np.array([4.5, 5, 6])]
113+
embeddings2 = [[1.5, 2, 3], [4.5, 5, 6]]
115114
await conn.execute("INSERT INTO asyncpg_items (embeddings) VALUES (ARRAY[$1, $2]::vector[])", embeddings2[0], embeddings2[1])
116115

117116
res = await conn.fetch("SELECT * FROM asyncpg_items ORDER BY id")
@@ -133,7 +132,7 @@ async def init(conn):
133132
await conn.execute('CREATE TABLE asyncpg_items (id bigserial PRIMARY KEY, embedding vector(3))')
134133

135134
embedding = Vector([1.5, 2, 3])
136-
embedding2 = np.array([1.5, 2, 3])
135+
embedding2 = [1.5, 2, 3]
137136
await conn.execute("INSERT INTO asyncpg_items (embedding) VALUES ($1), ($2), (NULL)", embedding, embedding2)
138137

139138
res = await conn.fetch("SELECT * FROM asyncpg_items ORDER BY id")

0 commit comments

Comments
 (0)