Clarify persistence paths and preserve archive compatibility - #23
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this change
Persistence already had a stable archive shape, but some important boundaries were left implicit. Empty paths could be mistaken for an omitted
save()destination, path-like objects were accepted through implementation details rather than an explicit contract, and users had to infer which exception type would surface when opening a bad file. The project also said that format-version-1 archives remained readable without testing an archive produced by an older published release.This PR makes those behaviors deliberate and testable before 0.6.0. It does not introduce a new archive format or a package-specific exception hierarchy.
What changes
open()andsave()now explicitly accept strings and string-valuedos.PathLikeobjects, includingpathlib.Pathand custom path-like types.ValueErrorinstead of being treated like an omitted path.None, bytes, booleans, numbers, and other non-path values passed toopen()raiseTypeError. Explicit non-path values passed tosave()do the same.save(None)keeps its existing meaning: reuse the store's current file binding, or raiseValueErrorwhen no binding exists..npzfor save and open operations.Archive compatibility and failures
The compatibility suite now opens a checked-in 1,199-byte archive created by the published
numpy-vector-store==0.4.0wheel on Python 3.11 with NumPy 1.23.2. The fixture contains built-in metadata, has a recorded SHA-256 digest, and verifies the complete restored configuration, vectors, metadata, and file binding. Using a real published artifact prevents current writer code from accidentally validating itself.The compatibility promise remains intentionally one-way and narrow: current releases can read the recorded self-describing format-version-1 archive. This does not restore support for unversioned archives, guarantee that 0.4 can read future formats, or promise portability for pickled application objects whose classes or dependencies are unavailable.
Persistence errors also keep the exception type owned by the failing layer. Filesystem failures remain
OSErrorsubclasses, invalid archive schemas remainValueError, and NumPy, pickle, or application metadata-loading exceptions are allowed to surface without being collapsed into a package-specific wrapper. Exact error text is not a compatibility guarantee.User impact
Valid persistence calls remain unchanged. Users gain predictable feedback for bad path inputs, can rely on normal string-valued path-like objects, and can catch the native exception that best describes a filesystem, schema, or deserialization failure. Applications that intentionally passed an empty string as if it meant
save()without a destination should usesave()orsave(None)instead.Because metadata remains pickle-backed, archives are still trusted input and should not be opened from untrusted or unverifiable sources.
Documentation and ancillary changes
Verification
uv run ruff check .uv run ruff format --check .uv run mypy srcuv run pytest -q— 294 tests passed on the locked Python 3.13 environmentuv run --isolated --python 3.11 --with numpy==1.23.2 --with pytest==8.4.2 --with-editable . pytest -W error -q— 294 tests passed on the minimum supported Python and NumPy boundary570f837ac7652a860fb2ee41abe36a0e028318903ea55e0eeee3daa269119894, matching its recorded provenance.Commit organization