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.
Files changed (29) hide show
  1. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/.github/workflows/checks.yml +33 -7
  2. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/.github/workflows/publish-pypi.yml +8 -3
  3. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/.github/workflows/publish-testpypi.yml +6 -3
  4. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/CHANGELOG.md +110 -1
  5. numpy_vector_store-0.7.0/COMPATIBILITY.md +145 -0
  6. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/MIGRATION.md +10 -5
  7. numpy_vector_store-0.6.0/README.md → numpy_vector_store-0.7.0/PKG-INFO +65 -14
  8. numpy_vector_store-0.6.0/PKG-INFO → numpy_vector_store-0.7.0/README.md +42 -37
  9. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/ROADMAP.md +74 -6
  10. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/pyproject.toml +4 -3
  11. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/src/numpy_vector_store/__init__.py +2 -2
  12. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/src/numpy_vector_store/vector_store.py +12 -6
  13. numpy_vector_store-0.7.0/tests/test_package.py +34 -0
  14. numpy_vector_store-0.7.0/tests/test_release_version.py +111 -0
  15. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/tests/test_vector_store.py +157 -1
  16. numpy_vector_store-0.7.0/tools/verify_release_version.py +169 -0
  17. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/.github/FUNDING.yml +0 -0
  18. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/.gitignore +0 -0
  19. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/LICENSE +0 -0
  20. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/benchmarks/README.md +0 -0
  21. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/benchmarks/__init__.py +0 -0
  22. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/benchmarks/benchmark.py +0 -0
  23. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/justfile +0 -0
  24. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/src/numpy_vector_store/py.typed +0 -0
  25. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/tests/__init__.py +0 -0
  26. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/tests/fixtures/README.md +0 -0
  27. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/tests/fixtures/vector-store-0.4.0-format-v1.npz +0 -0
  28. {numpy_vector_store-0.6.0 → numpy_vector_store-0.7.0}/tests/test_benchmark.py +0 -0
  29. {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
@@ -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.6.0 - 2026-08-21
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
- vector, payload = store.get(0)
75
-
76
- vector[0] = 10.0 # Independent copy; the store is unchanged.
77
- payload["reviewed"] = True # Shared application metadata object.
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
- - **Portable persistence** as versioned, self-describing trusted local `.npz` files
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
- vector, payload = store.get(0)
171
-
172
- vector[0] = 10.0 # Independent copy; the store is unchanged.
173
- payload["reviewed"] = True # Shared application metadata object.
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`, and search thresholds must also be
225
- finite. Invalid values are rejected before they can affect stored state or
226
- ranking.
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.6 reads only self-describing format version 1 archives. Unversioned
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.6 supports Python 3.11 through 3.14 and NumPy 1.23.2 or newer. These
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 run ruff check`
483
- 2. Run `uv run ruff format --check`
484
- 3. Run `uv run mypy src/`
485
- 4. Run `uv run pytest`
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