numpy-vector-store 0.5.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.5.0 → numpy_vector_store-0.7.0}/.github/workflows/checks.yml +33 -7
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/.github/workflows/publish-pypi.yml +8 -3
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/.github/workflows/publish-testpypi.yml +6 -3
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/CHANGELOG.md +251 -0
- numpy_vector_store-0.7.0/COMPATIBILITY.md +145 -0
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/MIGRATION.md +25 -4
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/PKG-INFO +153 -31
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/README.md +149 -27
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/ROADMAP.md +140 -17
- numpy_vector_store-0.7.0/benchmarks/README.md +91 -0
- numpy_vector_store-0.7.0/benchmarks/__init__.py +1 -0
- numpy_vector_store-0.7.0/benchmarks/benchmark.py +335 -0
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/pyproject.toml +4 -3
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/src/numpy_vector_store/__init__.py +2 -2
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/src/numpy_vector_store/vector_store.py +131 -49
- numpy_vector_store-0.7.0/tests/fixtures/README.md +36 -0
- numpy_vector_store-0.7.0/tests/fixtures/vector-store-0.4.0-format-v1.npz +0 -0
- numpy_vector_store-0.7.0/tests/test_benchmark.py +119 -0
- 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.5.0 → numpy_vector_store-0.7.0}/tests/test_vector_store.py +520 -28
- numpy_vector_store-0.7.0/tools/verify_release_version.py +169 -0
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/.github/FUNDING.yml +0 -0
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/.gitignore +0 -0
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/LICENSE +0 -0
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/justfile +0 -0
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/src/numpy_vector_store/py.typed +0 -0
- {numpy_vector_store-0.5.0 → numpy_vector_store-0.7.0}/tests/__init__.py +0 -0
- {numpy_vector_store-0.5.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.5.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,6 +4,257 @@ 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 - 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
|
|
117
|
+
|
|
118
|
+
This release makes the existing API's input and failure contracts predictable
|
|
119
|
+
before 1.0. It closes cases where the same invalid call could behave
|
|
120
|
+
differently on an empty and populated store, where Python booleans could act as
|
|
121
|
+
row indexes or counts, and where loosely coerced configuration could change
|
|
122
|
+
meaning after persistence. It also turns the project's performance claims and
|
|
123
|
+
format-version-1 compatibility promise into reproducible regression evidence.
|
|
124
|
+
|
|
125
|
+
Valid, documented 0.5 usage continues to work unchanged. Version 0.6 does not
|
|
126
|
+
add a new feature family, archive format, runtime dependency, or public
|
|
127
|
+
exception hierarchy.
|
|
128
|
+
|
|
129
|
+
### API at a glance
|
|
130
|
+
|
|
131
|
+
The complete workflow remains centered on `VectorStore` and `VectorHit`:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
store = VectorStore(dimensions=1536, normalize=True)
|
|
135
|
+
store.add(vectors, metadata)
|
|
136
|
+
|
|
137
|
+
hits = store.cosine_search(query, top_k=10)
|
|
138
|
+
hits = store.dot_search(query, top_k=10, min_value=0.5)
|
|
139
|
+
hits = store.euclidean_search(query, top_k=10, within_rows=row_indexes)
|
|
140
|
+
|
|
141
|
+
row = store.get(0)
|
|
142
|
+
store.clear()
|
|
143
|
+
|
|
144
|
+
store.save("vectors.npz")
|
|
145
|
+
store.save()
|
|
146
|
+
|
|
147
|
+
loaded = VectorStore.open("vectors.npz")
|
|
148
|
+
loaded.reload()
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The ownership, amortized ingestion, deterministic tie ordering, explicit
|
|
152
|
+
persistence lifecycle, and trusted-local-file boundary established in 0.5 are
|
|
153
|
+
unchanged.
|
|
154
|
+
|
|
155
|
+
### Predictable scalar inputs
|
|
156
|
+
|
|
157
|
+
- Accept Python integers, NumPy integer scalars, and other values implementing
|
|
158
|
+
the standard integer-index protocol for `dimensions`, `top_k`, and
|
|
159
|
+
`get(index)`, then convert them to a Python `int`.
|
|
160
|
+
- Reject Python and NumPy booleans where integer semantics are required.
|
|
161
|
+
`top_k=True` no longer means one, and `get(True)` no longer invokes NumPy
|
|
162
|
+
boolean indexing.
|
|
163
|
+
- Continue requiring positive `dimensions` and `top_k` values. A valid integer
|
|
164
|
+
outside the stored row range still makes `get()` return `None`.
|
|
165
|
+
- Accept Python and NumPy booleans for `normalize`, then retain a canonical
|
|
166
|
+
Python `bool` in memory and persistence.
|
|
167
|
+
- Accept finite Python and NumPy integer or floating-point scalars for
|
|
168
|
+
`min_value` and `max_value`. Reject booleans, strings, complex values,
|
|
169
|
+
arrays, and non-finite thresholds before search.
|
|
170
|
+
|
|
171
|
+
An inappropriate scalar type now raises `TypeError`, while a supported type
|
|
172
|
+
with an invalid value raises `ValueError`. Row bounds continue using
|
|
173
|
+
`IndexError` where row selectors require an existing row. Exact error wording
|
|
174
|
+
remains explanatory rather than a compatibility guarantee.
|
|
175
|
+
|
|
176
|
+
### Search checks independent of store state
|
|
177
|
+
|
|
178
|
+
- Validate `within_rows` before returning an empty result. It must be a
|
|
179
|
+
one-dimensional sequence of unique integer row indexes, without booleans,
|
|
180
|
+
and every index must be within the current store.
|
|
181
|
+
- Reject duplicate filtered indexes instead of returning the same stored row
|
|
182
|
+
more than once.
|
|
183
|
+
- Apply the same zero-query rules before the empty-store shortcut. Cosine
|
|
184
|
+
search always requires a non-zero query. Dot-product and Euclidean searches
|
|
185
|
+
require one when the store normalizes vectors, while raw stores continue to
|
|
186
|
+
accept a zero query for those two metrics.
|
|
187
|
+
- Keep selector validation vectorized for native NumPy integer arrays and avoid
|
|
188
|
+
changing process-global warning filters while validating Python sequences.
|
|
189
|
+
|
|
190
|
+
These changes affect preconditions, not ranking. Valid 0.5 searches retain the
|
|
191
|
+
same metric calculations, thresholds, deterministic tie handling, filtered-row
|
|
192
|
+
semantics, and `VectorHit` results.
|
|
193
|
+
|
|
194
|
+
### Persistence inputs and compatibility boundaries
|
|
195
|
+
|
|
196
|
+
- Accept strings and string-returning path-like objects for `open()`,
|
|
197
|
+
`save(path)`, and bound archive paths. Reject an explicitly empty path with
|
|
198
|
+
`ValueError` and an inappropriate path type, including bytes paths, with
|
|
199
|
+
`TypeError`.
|
|
200
|
+
- Keep `save()` with no argument distinct from `save("")`: omission means
|
|
201
|
+
"save to the current binding," while an empty string is an invalid path.
|
|
202
|
+
- Preserve extension resolution. A path without `.npz` still resolves to the
|
|
203
|
+
same archive for saving, opening, and reloading.
|
|
204
|
+
- Preserve owning exceptions at the persistence boundary. Filesystem failures
|
|
205
|
+
use the relevant `OSError` subclass, malformed archive schemas use
|
|
206
|
+
`ValueError`, and NumPy, pickle, or application metadata-loading failures are
|
|
207
|
+
not hidden inside a package-specific wrapper.
|
|
208
|
+
|
|
209
|
+
Archive format version 1 is unchanged. The compatibility suite now includes an
|
|
210
|
+
archive produced by the published 0.4.0 package on Python 3.11 with NumPy
|
|
211
|
+
1.23.2 and verifies that the current reader recovers its configuration, vectors,
|
|
212
|
+
and metadata. This is a forward-reading promise for the self-describing format,
|
|
213
|
+
not support for older unversioned two-array archives or a promise that an old
|
|
214
|
+
package can read an arbitrary future format. Persistence remains a trusted-file
|
|
215
|
+
feature because opaque metadata uses NumPy's pickle-backed object arrays.
|
|
216
|
+
|
|
217
|
+
### Reproducible performance evidence
|
|
218
|
+
|
|
219
|
+
- Add repository benchmark commands for public exact search and ingestion.
|
|
220
|
+
Each command records the workload, seeded input digests, complete timing
|
|
221
|
+
samples, median, Python and NumPy versions, Git state, timer, thread-related
|
|
222
|
+
environment variables, and NumPy build configuration as JSON.
|
|
223
|
+
- Measure prepared inputs and documented public operations rather than random
|
|
224
|
+
input generation. Search records complete query batches; ingestion records a
|
|
225
|
+
fresh store and every `add()` call.
|
|
226
|
+
- Add structural regression checks for geometric capacity reuse, partial
|
|
227
|
+
top-k selection, and unfiltered access to the stored vector matrix without a
|
|
228
|
+
preliminary full-matrix copy.
|
|
229
|
+
- Keep wall-clock limits out of shared CI, where runner load would make failures
|
|
230
|
+
noisy and machine-specific.
|
|
231
|
+
|
|
232
|
+
The README now reports one aligned grid at 1,000, 10,000, and 100,000 rows for
|
|
233
|
+
384, 1,536, and 3,072 dimensions, measured on a 24 GB Apple M4 Mac mini. It
|
|
234
|
+
also makes the intended scale explicit: this project is for small-to-medium,
|
|
235
|
+
in-process exact search. The 100,000-row measurements are an upper reference,
|
|
236
|
+
not a target for indefinite scaling; routinely million-row workloads generally
|
|
237
|
+
need an indexed or service-backed system.
|
|
238
|
+
|
|
239
|
+
### Runtime compatibility and upgrade notes
|
|
240
|
+
|
|
241
|
+
- Continue supporting Python 3.11 through 3.14 and NumPy 1.23.2 or newer.
|
|
242
|
+
- Continue exercising every supported Python version in CI, including a
|
|
243
|
+
dedicated Python 3.11 job with the minimum NumPy version.
|
|
244
|
+
- Keep the runtime wheel limited to the package. Benchmark tooling and its
|
|
245
|
+
guide are included in the source distribution without adding runtime
|
|
246
|
+
dependencies.
|
|
247
|
+
- Require no archive conversion when upgrading from 0.5; format version 1 is
|
|
248
|
+
still the only supported archive format.
|
|
249
|
+
|
|
250
|
+
Applications using documented 0.5 input types should not need code changes.
|
|
251
|
+
Review call sites that pass booleans where integers are expected, fractional
|
|
252
|
+
result counts, string or boolean thresholds, duplicate or malformed
|
|
253
|
+
`within_rows` values, zero queries that were only attempted against empty
|
|
254
|
+
stores, or explicitly empty persistence paths. Those accidentally accepted or
|
|
255
|
+
state-dependent cases now fail at the public boundary with consistent standard
|
|
256
|
+
exceptions.
|
|
257
|
+
|
|
7
258
|
## 0.5.0 - 2026-08-21
|
|
8
259
|
|
|
9
260
|
This release gives `VectorStore` clear ownership of its configuration and row
|
|
@@ -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
|
|
@@ -177,6 +178,15 @@ contents, loads its rows, and binds its path. Applications no longer need to
|
|
|
177
178
|
keep archive configuration separately or risk loading the same vectors with
|
|
178
179
|
different semantics.
|
|
179
180
|
|
|
181
|
+
Paths may be strings or string-valued `os.PathLike` objects such as
|
|
182
|
+
`pathlib.Path`. Empty paths raise `ValueError`, while bytes and other non-path
|
|
183
|
+
values raise `TypeError`. A `None` path is meaningful only for `save()`, where
|
|
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.
|
|
189
|
+
|
|
180
190
|
The generic parameter still describes application metadata. It can be kept
|
|
181
191
|
when useful:
|
|
182
192
|
|
|
@@ -284,6 +294,17 @@ configuration safely.
|
|
|
284
294
|
Metadata is stored in a pickle-backed NumPy object array. Archives remain
|
|
285
295
|
trusted input and must not be opened from untrusted or unverifiable sources.
|
|
286
296
|
|
|
297
|
+
Current releases retain forward-reading support for self-describing
|
|
298
|
+
format-version-1 archives written by 0.4. The test suite keeps a binary fixture
|
|
299
|
+
generated by the published 0.4.0 package on Python 3.11 and NumPy 1.23.2. This
|
|
300
|
+
does not restore the unversioned reader or promise that an older release can
|
|
301
|
+
read an arbitrary future format.
|
|
302
|
+
|
|
303
|
+
Read and write failures retain the exception type owned by their source:
|
|
304
|
+
filesystem `OSError` subclasses, schema `ValueError`, and NumPy, pickle, or
|
|
305
|
+
application metadata-loading errors are not collapsed into a package-specific
|
|
306
|
+
exception.
|
|
307
|
+
|
|
287
308
|
Saves use same-directory temporary files and atomic replacement, but the
|
|
288
309
|
library does not add file locking, coordinate concurrent writers, or promise
|
|
289
310
|
power-loss durability across every operating system and filesystem.
|