numpy-vector-store 0.6.0__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/.github/workflows/checks.yml +33 -7
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/.github/workflows/publish-pypi.yml +8 -3
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/.github/workflows/publish-testpypi.yml +6 -3
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/CHANGELOG.md +110 -1
- numpy_vector_store-0.7.0/COMPATIBILITY.md +145 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/MIGRATION.md +10 -5
- numpy_vector_store-0.6.0/README.md → numpy_vector_store-0.7.0/PKG-INFO +65 -14
- numpy_vector_store-0.6.0/PKG-INFO → numpy_vector_store-0.7.0/README.md +42 -37
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/ROADMAP.md +74 -6
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/pyproject.toml +4 -3
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/src/numpy_vector_store/__init__.py +2 -2
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/src/numpy_vector_store/vector_store.py +12 -6
- numpy_vector_store-0.7.0/tests/test_package.py +34 -0
- numpy_vector_store-0.7.0/tests/test_release_version.py +111 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/tests/test_vector_store.py +157 -1
- numpy_vector_store-0.7.0/tools/verify_release_version.py +169 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/.github/FUNDING.yml +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/.gitignore +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/LICENSE +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/benchmarks/README.md +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/benchmarks/__init__.py +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/benchmarks/benchmark.py +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/justfile +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/src/numpy_vector_store/py.typed +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/tests/__init__.py +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/tests/fixtures/README.md +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/tests/fixtures/vector-store-0.4.0-format-v1.npz +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/tests/test_benchmark.py +0 -0
- {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/uv.lock +0 -0
|
@@ -22,10 +22,10 @@ jobs:
|
|
|
22
22
|
|
|
23
23
|
steps:
|
|
24
24
|
- name: Check out repository
|
|
25
|
-
uses: actions/checkout@v6
|
|
25
|
+
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
26
26
|
|
|
27
27
|
- name: Set up Python
|
|
28
|
-
uses: actions/setup-python@v6
|
|
28
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
29
29
|
with:
|
|
30
30
|
python-version: "3.13"
|
|
31
31
|
|
|
@@ -46,7 +46,7 @@ jobs:
|
|
|
46
46
|
run: uv run --locked ruff format --check .
|
|
47
47
|
|
|
48
48
|
- name: Run mypy
|
|
49
|
-
run: uv run --locked mypy src/
|
|
49
|
+
run: uv run --locked mypy src/ benchmarks/ tools/
|
|
50
50
|
|
|
51
51
|
tests:
|
|
52
52
|
name: Test Python ${{ matrix.python-version }}
|
|
@@ -62,10 +62,10 @@ jobs:
|
|
|
62
62
|
|
|
63
63
|
steps:
|
|
64
64
|
- name: Check out repository
|
|
65
|
-
uses: actions/checkout@v6
|
|
65
|
+
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
66
66
|
|
|
67
67
|
- name: Set up Python
|
|
68
|
-
uses: actions/setup-python@v6
|
|
68
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
69
69
|
with:
|
|
70
70
|
python-version: ${{ matrix.python-version }}
|
|
71
71
|
|
|
@@ -82,16 +82,42 @@ jobs:
|
|
|
82
82
|
- name: Run tests
|
|
83
83
|
run: uv run --locked pytest
|
|
84
84
|
|
|
85
|
+
windows:
|
|
86
|
+
name: Test Windows on Python 3.13
|
|
87
|
+
runs-on: windows-latest
|
|
88
|
+
|
|
89
|
+
steps:
|
|
90
|
+
- name: Check out repository
|
|
91
|
+
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
92
|
+
|
|
93
|
+
- name: Set up Python
|
|
94
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
95
|
+
with:
|
|
96
|
+
python-version: "3.13"
|
|
97
|
+
|
|
98
|
+
- name: Set up uv
|
|
99
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
100
|
+
with:
|
|
101
|
+
version: "0.11.32"
|
|
102
|
+
python-version: "3.13"
|
|
103
|
+
enable-cache: true
|
|
104
|
+
|
|
105
|
+
- name: Install project dependencies
|
|
106
|
+
run: uv sync --locked --group dev
|
|
107
|
+
|
|
108
|
+
- name: Run tests
|
|
109
|
+
run: uv run --locked pytest
|
|
110
|
+
|
|
85
111
|
minimum-numpy:
|
|
86
112
|
name: Test minimum NumPy on Python 3.11
|
|
87
113
|
runs-on: ubuntu-latest
|
|
88
114
|
|
|
89
115
|
steps:
|
|
90
116
|
- name: Check out repository
|
|
91
|
-
uses: actions/checkout@v6
|
|
117
|
+
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
92
118
|
|
|
93
119
|
- name: Set up Python
|
|
94
|
-
uses: actions/setup-python@v6
|
|
120
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
95
121
|
with:
|
|
96
122
|
python-version: "3.11"
|
|
97
123
|
|
|
@@ -20,10 +20,10 @@ jobs:
|
|
|
20
20
|
|
|
21
21
|
steps:
|
|
22
22
|
- name: Check out repository
|
|
23
|
-
uses: actions/checkout@v6
|
|
23
|
+
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
24
24
|
|
|
25
25
|
- name: Set up Python
|
|
26
|
-
uses: actions/setup-python@v6
|
|
26
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
27
27
|
with:
|
|
28
28
|
python-version: "3.12"
|
|
29
29
|
|
|
@@ -33,8 +33,13 @@ jobs:
|
|
|
33
33
|
- name: Build distributions
|
|
34
34
|
run: python -m build
|
|
35
35
|
|
|
36
|
+
- name: Verify release versions
|
|
37
|
+
env:
|
|
38
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
39
|
+
run: python tools/verify_release_version.py --tag "$RELEASE_TAG"
|
|
40
|
+
|
|
36
41
|
- name: Check distribution metadata
|
|
37
42
|
run: python -m twine check dist/*
|
|
38
43
|
|
|
39
44
|
- name: Publish package distributions to PyPI
|
|
40
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
45
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
{numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/.github/workflows/publish-testpypi.yml
RENAMED
|
@@ -18,10 +18,10 @@ jobs:
|
|
|
18
18
|
|
|
19
19
|
steps:
|
|
20
20
|
- name: Check out repository
|
|
21
|
-
uses: actions/checkout@v6
|
|
21
|
+
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
22
22
|
|
|
23
23
|
- name: Set up Python
|
|
24
|
-
uses: actions/setup-python@v6
|
|
24
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
25
25
|
with:
|
|
26
26
|
python-version: "3.12"
|
|
27
27
|
|
|
@@ -31,10 +31,13 @@ jobs:
|
|
|
31
31
|
- name: Build distributions
|
|
32
32
|
run: python -m build
|
|
33
33
|
|
|
34
|
+
- name: Verify distribution versions
|
|
35
|
+
run: python tools/verify_release_version.py
|
|
36
|
+
|
|
34
37
|
- name: Check distribution metadata
|
|
35
38
|
run: python -m twine check dist/*
|
|
36
39
|
|
|
37
40
|
- name: Publish package distributions to TestPyPI
|
|
38
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
41
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
39
42
|
with:
|
|
40
43
|
repository-url: https://test.pypi.org/legacy/
|
|
@@ -4,7 +4,116 @@ This changelog records user-visible changes to NumPy Vector Store. Earlier
|
|
|
4
4
|
release notes remain available on the
|
|
5
5
|
[GitHub releases page](https://github.com/tvanreenen/numpy-vector-store/releases).
|
|
6
6
|
|
|
7
|
-
## 0.
|
|
7
|
+
## 0.7.0 - 2026-08-24
|
|
8
|
+
|
|
9
|
+
This release closes the remaining public contract gaps found during the 1.0
|
|
10
|
+
readiness audit. It rejects two forms of lossy NumPy coercion, makes a bound
|
|
11
|
+
archive path stable for the lifetime of its store, and publishes the API and
|
|
12
|
+
compatibility policy intended for 1.x. It also adds release checks that enforce
|
|
13
|
+
the package version and distribution metadata before publication.
|
|
14
|
+
|
|
15
|
+
Valid, documented 0.6 usage continues to work. Version 0.7 does not add a new
|
|
16
|
+
feature family, remove a documented API, change search ranking, add a runtime
|
|
17
|
+
dependency, or change archive format version 1.
|
|
18
|
+
|
|
19
|
+
### Public API and 1.x compatibility policy
|
|
20
|
+
|
|
21
|
+
The supported package-level imports are now explicit:
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from numpy_vector_store import VectorHit, VectorStore, __version__
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- Add a [public API and compatibility policy](COMPATIBILITY.md) that names the
|
|
28
|
+
supported `VectorStore` methods and properties, `VectorHit` fields, return
|
|
29
|
+
types, ownership behavior, exception classes, and persistence guarantees.
|
|
30
|
+
- Distinguish the supported top-level interface from private helpers, submodule
|
|
31
|
+
layout, subclass hooks, exact error wording, allocation details, and internal
|
|
32
|
+
algorithms.
|
|
33
|
+
- Define the 1.x semantic-versioning, deprecation, removal, Python and NumPy
|
|
34
|
+
support, and archive-compatibility policies before those promises become
|
|
35
|
+
long-term commitments in 1.0.
|
|
36
|
+
- Keep `VectorHit` as an immutable result record whose equality and hashability
|
|
37
|
+
follow its three values. Opaque metadata retains its own comparison and
|
|
38
|
+
hashing behavior; a hit containing a dictionary remains unhashable.
|
|
39
|
+
|
|
40
|
+
The API itself remains centered on `VectorStore`, `VectorHit`, three explicit
|
|
41
|
+
metric methods, typed opaque metadata, and the create/open/save/reload
|
|
42
|
+
persistence lifecycle.
|
|
43
|
+
|
|
44
|
+
### Lossless numeric input handling
|
|
45
|
+
|
|
46
|
+
- Reject Python row-selector sequences containing a Python or NumPy Boolean,
|
|
47
|
+
including mixed values such as `[0, True]`, before NumPy can coerce the
|
|
48
|
+
Boolean to row zero or one.
|
|
49
|
+
- Preserve the vectorized validation path for native NumPy integer selectors,
|
|
50
|
+
along with the existing shape, uniqueness, and bounds rules.
|
|
51
|
+
- Reject complex vector batches passed to `add()` and complex queries passed to
|
|
52
|
+
every metric method before conversion to `float32` can discard their
|
|
53
|
+
imaginary components. This includes complex dtypes whose current values have
|
|
54
|
+
a zero imaginary part.
|
|
55
|
+
- Apply complex-query validation before empty-store and empty-filter shortcuts,
|
|
56
|
+
so the accepted query contract does not depend on current store state.
|
|
57
|
+
|
|
58
|
+
These inputs were accepted only through implicit NumPy conversion. Calls that
|
|
59
|
+
deliberately used Boolean row indexes or complex vectors now raise `TypeError`;
|
|
60
|
+
real-valued integer and floating-point inputs keep their existing behavior.
|
|
61
|
+
|
|
62
|
+
### Stable archive bindings
|
|
63
|
+
|
|
64
|
+
- Anchor a relative path to the current working directory when `save(path)` or
|
|
65
|
+
`VectorStore.open(path)` first binds it.
|
|
66
|
+
- Return that anchored absolute path from `file_path` and keep later `save()` and
|
|
67
|
+
`reload()` calls pointed at the same archive if the process changes working
|
|
68
|
+
directory.
|
|
69
|
+
- Preserve extensionless `.npz` resolution and lexical path behavior. Anchoring
|
|
70
|
+
does not resolve `..` components or dereference symlinks, so ordinary
|
|
71
|
+
filesystem replacement semantics remain intact.
|
|
72
|
+
- Keep Save As transactional: a new binding becomes visible only after the new
|
|
73
|
+
archive has been written successfully.
|
|
74
|
+
|
|
75
|
+
Format version 1 is unchanged, and no archive conversion is required. Code that
|
|
76
|
+
compares `file_path` with a relative path should compare against its anchored
|
|
77
|
+
absolute form. Code that intentionally changed directories to redirect a later
|
|
78
|
+
pathless save should pass the new destination explicitly to `save(path)`.
|
|
79
|
+
|
|
80
|
+
### Distribution and release safeguards
|
|
81
|
+
|
|
82
|
+
- Publish the MIT license as an SPDX expression and include `LICENSE` in both
|
|
83
|
+
the wheel and source distribution.
|
|
84
|
+
- Declare the existing `py.typed` marker through the `Typing :: Typed`
|
|
85
|
+
classifier and identify 0.7 as the project's beta adoption cycle before 1.0.
|
|
86
|
+
- Verify that the source `__version__`, GitHub release tag, wheel metadata, and
|
|
87
|
+
source-distribution metadata agree before publishing to PyPI. The verifier
|
|
88
|
+
also requires exactly one wheel and one source distribution so stale build
|
|
89
|
+
output cannot be uploaded accidentally.
|
|
90
|
+
- Pin remote GitHub Actions to immutable commits while retaining readable
|
|
91
|
+
release comments beside each pin.
|
|
92
|
+
- Run the complete test suite on Windows with Python 3.13 in addition to the
|
|
93
|
+
supported Python 3.11 through 3.14 matrix on Linux and the Python 3.11 minimum
|
|
94
|
+
NumPy check.
|
|
95
|
+
- Add regression coverage for unexpected archive fields, nonpositive persisted
|
|
96
|
+
dimensions, malformed persisted array shapes, and platform-specific
|
|
97
|
+
filesystem exception and permission behavior.
|
|
98
|
+
|
|
99
|
+
The release verifier and benchmark tools remain outside the runtime wheel and
|
|
100
|
+
add no package dependency.
|
|
101
|
+
|
|
102
|
+
### Runtime compatibility and upgrade notes
|
|
103
|
+
|
|
104
|
+
- Continue supporting Python 3.11 through 3.14 and NumPy 1.23.2 or newer.
|
|
105
|
+
- Continue reading and writing self-describing format-version-1 archives,
|
|
106
|
+
including archives created by the published 0.4 package.
|
|
107
|
+
- Continue treating persistence as a trusted-file feature because opaque
|
|
108
|
+
metadata uses pickle-backed NumPy object arrays.
|
|
109
|
+
- Require no data migration when upgrading from 0.6.
|
|
110
|
+
|
|
111
|
+
Most applications can upgrade without code changes. Review only code that used
|
|
112
|
+
Boolean row selectors, supplied complex vectors or queries, compared a bound
|
|
113
|
+
`file_path` with a relative path, or relied on a later working-directory change
|
|
114
|
+
to redirect a bound store.
|
|
115
|
+
|
|
116
|
+
## 0.6.0 - 2026-08-22
|
|
8
117
|
|
|
9
118
|
This release makes the existing API's input and failure contracts predictable
|
|
10
119
|
before 1.0. It closes cases where the same invalid call could behave
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Public API and compatibility policy
|
|
2
|
+
|
|
3
|
+
NumPy Vector Store 0.7 publishes the contract intended for 1.0 so applications
|
|
4
|
+
can evaluate it before the project makes a long-term stability commitment. The
|
|
5
|
+
package remains pre-1.0 until the 0.7 API has completed a normal release cycle.
|
|
6
|
+
|
|
7
|
+
This policy separates the small supported interface from implementation details
|
|
8
|
+
that may continue to improve during 1.x.
|
|
9
|
+
|
|
10
|
+
## Supported public API
|
|
11
|
+
|
|
12
|
+
Import supported names from the top-level package:
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
from numpy_vector_store import VectorHit, VectorStore, __version__
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
These are the package-level public names declared by `numpy_vector_store.__all__`:
|
|
19
|
+
|
|
20
|
+
- `VectorStore`, including its constructor, `len(store)`, and the documented
|
|
21
|
+
methods and properties below.
|
|
22
|
+
- `VectorHit`, including its read-only `index`, `value`, and `metadata` fields.
|
|
23
|
+
- `__version__`, the installed package version as a string.
|
|
24
|
+
|
|
25
|
+
The supported `VectorStore` surface is:
|
|
26
|
+
|
|
27
|
+
| Area | Public interface |
|
|
28
|
+
|---|---|
|
|
29
|
+
| Create | `VectorStore(dimensions, *, normalize=True)` |
|
|
30
|
+
| Inspect configuration | `dimensions`, `normalize`, `file_path` |
|
|
31
|
+
| Inspect rows | `vectors`, `metadata`, `len(store)` |
|
|
32
|
+
| Change rows | `add(vectors, metadata)`, `clear()` |
|
|
33
|
+
| Retrieve one row | `get(index)` |
|
|
34
|
+
| Search | `cosine_search(...)`, `dot_search(...)`, `euclidean_search(...)` |
|
|
35
|
+
| Persist | `VectorStore.open(path)`, `save(path)`, `save()`, `reload()` |
|
|
36
|
+
|
|
37
|
+
The public contract includes documented signatures, accepted input categories,
|
|
38
|
+
return types, public type annotations, state and ownership behavior, search
|
|
39
|
+
ordering, and exception classes. The `VectorStore` generic parameter describes
|
|
40
|
+
its metadata payload type and flows through row retrieval and search results.
|
|
41
|
+
The contract also includes the documented `float32` vector representation and
|
|
42
|
+
format-version-1 archive schema. Exact exception messages are explanatory text,
|
|
43
|
+
not identifiers for application logic.
|
|
44
|
+
|
|
45
|
+
Importing from `numpy_vector_store.vector_store` may work, but the submodule
|
|
46
|
+
layout is an implementation detail. Applications should use top-level imports.
|
|
47
|
+
Names beginning with a single underscore, private object state, spare-capacity
|
|
48
|
+
layout, and internal calculation steps are not public API.
|
|
49
|
+
|
|
50
|
+
`VectorStore` is not designed as a subclass extension framework. Subclassing is
|
|
51
|
+
not prohibited, but overriding methods or depending on private helpers and state
|
|
52
|
+
is outside the compatibility promise. Prefer composition when application code
|
|
53
|
+
needs behavior around a store.
|
|
54
|
+
|
|
55
|
+
## `VectorHit` and opaque metadata
|
|
56
|
+
|
|
57
|
+
`VectorHit` is an immutable result record. Its fields cannot be reassigned, but
|
|
58
|
+
the `metadata` value remains the same opaque application object held by the
|
|
59
|
+
store. A mutable metadata payload can still be changed through that object.
|
|
60
|
+
|
|
61
|
+
Equality and hashability follow the values stored in the three fields. There is
|
|
62
|
+
no package-specific metadata comparison or hashing policy. In particular:
|
|
63
|
+
|
|
64
|
+
- A hit containing a dictionary or another unhashable payload is unhashable.
|
|
65
|
+
- A metadata type with non-Boolean equality, such as a NumPy array, can make
|
|
66
|
+
whole-hit equality return a non-Boolean value or raise when converted to a
|
|
67
|
+
truth value.
|
|
68
|
+
- A metadata type with application-defined equality keeps those semantics.
|
|
69
|
+
|
|
70
|
+
Use `hit.index` or an immutable application identifier inside `hit.metadata`
|
|
71
|
+
when code needs a stable key. Do not assume every possible metadata payload
|
|
72
|
+
makes the complete `VectorHit` suitable for a set, dictionary key, or Boolean
|
|
73
|
+
equality assertion.
|
|
74
|
+
|
|
75
|
+
## Semantic versioning after 1.0
|
|
76
|
+
|
|
77
|
+
Starting with 1.0, release numbers follow
|
|
78
|
+
[Semantic Versioning 2.0.0](https://semver.org/) and communicate changes to the
|
|
79
|
+
documented public API:
|
|
80
|
+
|
|
81
|
+
- Patch releases contain backward-compatible defect fixes, documentation
|
|
82
|
+
corrections, and internal improvements. A patch may correct behavior that
|
|
83
|
+
contradicts the documented contract, and the release notes will identify the
|
|
84
|
+
affected case.
|
|
85
|
+
- Minor releases add backward-compatible functionality and may deprecate public
|
|
86
|
+
API. They do not remove or incompatibly change documented public API.
|
|
87
|
+
- Major releases may remove deprecated API or make other incompatible public
|
|
88
|
+
contract changes.
|
|
89
|
+
|
|
90
|
+
A public API deprecation will appear in the documentation and changelog and
|
|
91
|
+
will emit a warning where a runtime warning is practical. Removal waits for a
|
|
92
|
+
later major release and will have at least one minor release of prior
|
|
93
|
+
deprecation.
|
|
94
|
+
|
|
95
|
+
Exact error wording, object representations, private names, submodule layout,
|
|
96
|
+
internal algorithms, allocation strategy, benchmark timings, and undocumented
|
|
97
|
+
side effects may change in any release. Changes to these details must still
|
|
98
|
+
preserve the documented results and ownership rules.
|
|
99
|
+
|
|
100
|
+
## Archive compatibility
|
|
101
|
+
|
|
102
|
+
Archive format versions are independent of package versions. Format version 1
|
|
103
|
+
is the stable persistence contract for 1.x:
|
|
104
|
+
|
|
105
|
+
- Every 1.x release will continue reading and writing valid format-version-1
|
|
106
|
+
archives.
|
|
107
|
+
- A mandatory replacement for format version 1 requires a major package
|
|
108
|
+
release and a documented migration path.
|
|
109
|
+
- A new archive format may appear during 1.x only as an explicit opt-in while
|
|
110
|
+
format-version-1 read and write support remains available.
|
|
111
|
+
- An older reader is not expected to understand an arbitrary newer archive
|
|
112
|
+
format. Compatibility is a newer-reader promise, not a future-format promise
|
|
113
|
+
for already published code.
|
|
114
|
+
|
|
115
|
+
Unversioned archives containing only `vectors` and `metadata` remain outside
|
|
116
|
+
this contract because they do not record dimensions or normalization semantics.
|
|
117
|
+
|
|
118
|
+
Format compatibility does not make every Python metadata object portable.
|
|
119
|
+
Opaque metadata uses pickle-backed NumPy object arrays and may depend on the
|
|
120
|
+
same application classes, import paths, and compatible dependencies being
|
|
121
|
+
available when it is opened. Archives must come from a trusted source. The
|
|
122
|
+
library does not treat untrusted pickle data as safe input.
|
|
123
|
+
|
|
124
|
+
## Python and NumPy support
|
|
125
|
+
|
|
126
|
+
The Python versions listed in package metadata are tested in CI. The declared
|
|
127
|
+
minimum NumPy version is tested with the oldest supported Python version.
|
|
128
|
+
|
|
129
|
+
Support for a Python or NumPy version may be removed in a minor release after
|
|
130
|
+
its relevant upstream support window or ecosystem compatibility makes continued
|
|
131
|
+
testing impractical. Such a change will be made in package metadata and called
|
|
132
|
+
out in the changelog and release notes. Dropping a runtime version does not
|
|
133
|
+
remove callable API from applications running on a supported interpreter.
|
|
134
|
+
|
|
135
|
+
## Performance expectations
|
|
136
|
+
|
|
137
|
+
Search results, metric definitions, threshold behavior, deterministic tie
|
|
138
|
+
ordering, and filtered-row semantics are public behavior. The implementation
|
|
139
|
+
may change how it produces those results.
|
|
140
|
+
|
|
141
|
+
Published benchmark measurements are reference evidence, not latency or memory
|
|
142
|
+
guarantees. Hardware, NumPy, BLAS, process load, vector shape, and metadata all
|
|
143
|
+
affect observed performance. Structural regressions such as repeated full-store
|
|
144
|
+
copies during ordinary ingestion or unnecessary unfiltered search copies remain
|
|
145
|
+
covered by tests rather than fixed wall-clock promises.
|
|
@@ -71,10 +71,11 @@ payload objects by reference.
|
|
|
71
71
|
Row retrieval deliberately treats vectors and metadata differently:
|
|
72
72
|
|
|
73
73
|
```python
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
vector
|
|
77
|
-
|
|
74
|
+
row = store.get(0)
|
|
75
|
+
if row is not None:
|
|
76
|
+
vector, payload = row
|
|
77
|
+
vector[0] = 10.0 # Independent copy; the store is unchanged.
|
|
78
|
+
payload["reviewed"] = True # Shared application metadata object.
|
|
78
79
|
```
|
|
79
80
|
|
|
80
81
|
Vectors have one uniform NumPy representation, so copying a single row gives
|
|
@@ -180,7 +181,11 @@ different semantics.
|
|
|
180
181
|
Paths may be strings or string-valued `os.PathLike` objects such as
|
|
181
182
|
`pathlib.Path`. Empty paths raise `ValueError`, while bytes and other non-path
|
|
182
183
|
values raise `TypeError`. A `None` path is meaningful only for `save()`, where
|
|
183
|
-
it reuses an existing binding.
|
|
184
|
+
it reuses an existing binding. A relative path is anchored to the current
|
|
185
|
+
working directory when `save(path)` or `open(path)` binds it. The public
|
|
186
|
+
`file_path` is therefore absolute, and later working-directory changes do not
|
|
187
|
+
redirect pathless saves or reloads. Symlinks and `..` components are not
|
|
188
|
+
canonicalized.
|
|
184
189
|
|
|
185
190
|
The generic parameter still describes application metadata. It can be kept
|
|
186
191
|
when useful:
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: numpy-vector-store
|
|
3
|
+
Version: 0.7.0
|
|
4
|
+
Summary: A fast, lightweight, and zero-setup in-memory vector store powered by NumPy
|
|
5
|
+
Project-URL: Homepage, https://github.com/tvanreenen/numpy-vector-store
|
|
6
|
+
Project-URL: Repository, https://github.com/tvanreenen/numpy-vector-store
|
|
7
|
+
Project-URL: Issues, https://github.com/tvanreenen/numpy-vector-store/issues
|
|
8
|
+
Author: Tim VanReenen
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: embeddings,numpy,search,store,vector
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: numpy>=1.23.2
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
1
24
|
# NumPy Vector Store
|
|
2
25
|
|
|
3
26
|
A fast, lightweight, zero-setup in-memory vector store powered by NumPy.
|
|
@@ -6,7 +29,8 @@ A fast, lightweight, zero-setup in-memory vector store powered by NumPy.
|
|
|
6
29
|
- **Fast exact vector search** using vectorized NumPy operations
|
|
7
30
|
- **Simple typed API** returning `VectorHit(index, value, metadata)`
|
|
8
31
|
- **Composable filtering** by passing prefiltered row indexes with `within_rows`
|
|
9
|
-
- **
|
|
32
|
+
- **Single-file persistence** as versioned, self-describing trusted local
|
|
33
|
+
`.npz` archives
|
|
10
34
|
- **No framework opinions**: bring your own embeddings, chunking, async, and metadata model
|
|
11
35
|
|
|
12
36
|
## Why?
|
|
@@ -76,6 +100,12 @@ complexity checks in CI, but does not fail shared runners on wall-clock timing.
|
|
|
76
100
|
uv add numpy-vector-store
|
|
77
101
|
```
|
|
78
102
|
|
|
103
|
+
With pip:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
python -m pip install numpy-vector-store
|
|
107
|
+
```
|
|
108
|
+
|
|
79
109
|
## Quick Start
|
|
80
110
|
|
|
81
111
|
```python
|
|
@@ -111,6 +141,10 @@ Each payload can be a dict, dataclass, tuple, list, string, integer row ID, or
|
|
|
111
141
|
another Python object that fits your application. Tuple and list payloads remain
|
|
112
142
|
single row values rather than being interpreted as additional array dimensions.
|
|
113
143
|
|
|
144
|
+
The supported top-level package names are `VectorStore`, `VectorHit`, and
|
|
145
|
+
`__version__`. See the [public API and compatibility policy](COMPATIBILITY.md)
|
|
146
|
+
for the complete interface that the project intends to stabilize at 1.0.
|
|
147
|
+
|
|
114
148
|
## Scalar inputs and errors
|
|
115
149
|
|
|
116
150
|
`dimensions`, `top_k`, and the index passed to `get()` use integer semantics.
|
|
@@ -127,6 +161,9 @@ rejected.
|
|
|
127
161
|
|
|
128
162
|
`within_rows` must be a one-dimensional sequence of unique integer row indexes.
|
|
129
163
|
Python and NumPy integers are accepted; booleans and non-integer values are not.
|
|
164
|
+
When supplied as a Python sequence, this includes a boolean mixed into otherwise
|
|
165
|
+
integer values; NumPy's implicit conversion of that boolean to zero or one is
|
|
166
|
+
not used as a row index.
|
|
130
167
|
Malformed shapes and duplicate indexes raise `ValueError`, while an index
|
|
131
168
|
outside the current store raises `IndexError`. These checks still run when the
|
|
132
169
|
store is empty.
|
|
@@ -167,10 +204,11 @@ payload objects stored inside it.
|
|
|
167
204
|
`get(index)` has a narrower ownership boundary:
|
|
168
205
|
|
|
169
206
|
```python
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
vector
|
|
173
|
-
|
|
207
|
+
row = store.get(0)
|
|
208
|
+
if row is not None:
|
|
209
|
+
vector, payload = row
|
|
210
|
+
vector[0] = 10.0 # Independent copy; the store is unchanged.
|
|
211
|
+
payload["reviewed"] = True # Shared application metadata object.
|
|
174
212
|
```
|
|
175
213
|
|
|
176
214
|
The returned vector is an independent `float32` copy. The metadata payload is
|
|
@@ -221,9 +259,10 @@ rules apply even when the store or `within_rows` selection is empty.
|
|
|
221
259
|
### Numerical inputs
|
|
222
260
|
|
|
223
261
|
Stored vectors use `float32` to keep the store compact. Vectors and queries must
|
|
224
|
-
remain finite when converted to `float32
|
|
225
|
-
|
|
226
|
-
|
|
262
|
+
be real-valued array-like inputs that remain finite when converted to `float32`.
|
|
263
|
+
Complex-valued inputs raise `TypeError` rather than silently losing their
|
|
264
|
+
imaginary components. Search thresholds must also be finite. Invalid values are
|
|
265
|
+
rejected before they can affect stored state or ranking.
|
|
227
266
|
|
|
228
267
|
Norms and raw metric values use `float64` accumulation where `float32`
|
|
229
268
|
intermediate calculations could overflow or underflow. This allows finite
|
|
@@ -378,6 +417,12 @@ store.reload()
|
|
|
378
417
|
the file is missing, or the archive is invalid. A failed reload leaves the
|
|
379
418
|
current in-memory vectors and metadata unchanged.
|
|
380
419
|
|
|
420
|
+
When `save(path)` or `open(path)` receives a relative path, the store anchors it
|
|
421
|
+
to the current working directory as part of the binding. `file_path` therefore
|
|
422
|
+
returns an absolute path, and a later working-directory change cannot redirect
|
|
423
|
+
`save()` or `reload()` to another file. Anchoring does not canonicalize the path:
|
|
424
|
+
`..` components and symlinks retain their normal filesystem meaning.
|
|
425
|
+
|
|
381
426
|
The `.npz` suffix may be omitted. An extensionless path such as `"vectors"` is
|
|
382
427
|
resolved to `"vectors.npz"` for saving, opening, and reloading.
|
|
383
428
|
|
|
@@ -435,7 +480,7 @@ writers can still replace one another, and the library does not promise that a
|
|
|
435
480
|
successful save has reached durable hardware storage across every operating
|
|
436
481
|
system or power failure.
|
|
437
482
|
|
|
438
|
-
Version 0.
|
|
483
|
+
Version 0.7 reads only self-describing format version 1 archives. Unversioned
|
|
439
484
|
archives containing only `vectors` and `metadata` cannot be opened because they
|
|
440
485
|
do not record dimensions or normalization semantics. Recreate those archives
|
|
441
486
|
from source data, or convert them with NumPy Vector Store 0.4 before upgrading.
|
|
@@ -455,7 +500,12 @@ the API stabilizes. Changes are documented in the [changelog](CHANGELOG.md) and
|
|
|
455
500
|
GitHub release notes. Deprecated APIs will keep warning for at least one point
|
|
456
501
|
release before removal.
|
|
457
502
|
|
|
458
|
-
Version 0.
|
|
503
|
+
Version 0.7 publishes the proposed 1.x contract for an adoption cycle before
|
|
504
|
+
1.0. The [public API and compatibility policy](COMPATIBILITY.md) identifies the
|
|
505
|
+
supported top-level surface, deprecation rules, archive guarantees, runtime
|
|
506
|
+
support policy, and details that remain implementation-specific.
|
|
507
|
+
|
|
508
|
+
Version 0.7 supports Python 3.11 through 3.14 and NumPy 1.23.2 or newer. These
|
|
459
509
|
versions are listed in the package metadata and exercised in CI, including a
|
|
460
510
|
dedicated check against the minimum NumPy version. Python 3.10 remains supported
|
|
461
511
|
by the 0.3 release series but is not supported by 0.4 or later.
|
|
@@ -479,10 +529,11 @@ uv sync --frozen --group dev
|
|
|
479
529
|
|
|
480
530
|
Before submitting a pull request:
|
|
481
531
|
|
|
482
|
-
1. Run `uv
|
|
483
|
-
2. Run `uv run ruff
|
|
484
|
-
3. Run `uv run
|
|
485
|
-
4. Run `uv run
|
|
532
|
+
1. Run `uv lock --check`
|
|
533
|
+
2. Run `uv run --locked ruff check .`
|
|
534
|
+
3. Run `uv run --locked ruff format --check .`
|
|
535
|
+
4. Run `uv run --locked mypy src/ benchmarks/ tools/`
|
|
536
|
+
5. Run `uv run --locked pytest`
|
|
486
537
|
|
|
487
538
|
## License
|
|
488
539
|
|