Welcome to the key_multivalue_storage wiki!
JSON storage wrapper and editor. Created with love by Boss_1s.
Once upon a time, this was just a small project to solve a problem: the over-steep learning curve for scratchattach’s database functionality. Now, I have decided to make it a library, something with humble beginnings with big hopes in its future.
My mission now: a lightweight storage wrapper library that can be used anytime and anywhere, regardless of memory limits, sandbox limits, or usage limits.
It is strongly recommended to learn Python before using kms. The best environment to learn in is CPython 3.12 for this library.
Note
Please do note that throughout this repository, the library key-multivalue-storage may also be referred to as its repo/package name (key_multivalue_storage) or its abbreviation (kms).
🚀 What’s New in kms-semver1.3.2
💡 Features & Automation
- Version Bumping: Added a post-release script and automatic reminders to bump development versions (#153).
- Release Verification: Added automated checks to ensure the latest test deployment succeeds before completing a release (#153).
- Verbose Logging: Expanded release automation output for easier debugging.
🪲 Bug Fixes
- PATCHED UNMITIGATED BREAKING CHANGE. See
kms-v1.3.2/2026.10.12. - Workflow Tagging: Forced release tags onto the specific commits that modify the version number.
- Release Categorization: Corrected development builds to register as
pre-alphainstead ofbeta. - Fail-Safe Checks: Blocked scripts from continuing silently if required version environment variables are missing.
- Formatting: Fixed the layout format for release commit messages.
⏰ Infrastructure & CI
- Backports: Integrated multiple workflow stability fixes and commits backporting from the
semver1.4.xbranch. - Permissions: Expanded release script access to read Actions runs and automatically generate version-bump issues.
- Security & Actions: Pinned third-party workflow actions (
webfactory/ssh-agent,astral-sh/setup-uv,softprops/action-gh-release) to specific commits.
📢 Upcoming Roadmap
kms-semver1.3.3: Expected November 7th, 2026 (focusing on upstream backports and refactors).kms-semver1.3.4: Expected December 5th, 2026.kms-semver1.3.5: Expected December 21st, 2026.
🚀 What’s New in kms-semver1.4.0a0
Important
kms-semver1.4.x is officially built off of kms-v1.3.1/2026.08.12, and partially off of kms-v1.3.2/2026.09.30.
💡 Features & Automation
- Public API Cleanup: Added
atpublic-based visibility markers across the package and type stubs for a cleaner public/private API surface. - Storage Improvements: Added
Storage.update()and support for slice deletion withdel storage[start:stop]. - Testing Improvements: Expanded
kms.help()coverage and folded older issue-related tests into the main suite. - Release Automation: Improved nightly and release workflows so version generation and branch validation are more reliable.
🪲 Bug Fixes
- Slice Deletion Fix: Corrected
Storage.__delitem__so integer and slice deletion follow the correct logic. - Workflow Fixes: Resolved branch detection, deployment checks, and syntax issues in the automation workflows.
- Compatibility Fixes: Fixed
atpublicmetadata/type errors and cleaned up stale storage tests.
⏰ Infrastructure & CI
- Branch & Deployment Stability: Improved validation for supported
semver1.xbranches and pull request deployment checks. - Python Test Environment: Updated the test runner to CPython
3.15.0. - Dependency Refresh: Updated linting, docs, and test tooling across the
semver1.4.xbranch.
Important
Forward-ports from semver1.3.x are not included here. Check the semver1.3.x branch’s README for specific changes there.
Documentation
Resources
Contributor Resources
- Structure of the library
- Contributor Guidelines
- Changelog
- Development Help
- Roadmap
- Issues
- Pull Requests
You can contribute to this open-source project by forking this repo, making changes, then opening a pull request. Be sure to read through the guidelines!
Installation
Install with pip:
pip install -U key-multivalue-storage
Or, download the latest version of the .whl file here
You can also choose to download the development environment alongside the package:
pip install -U key-multivalue-storage[dev]
The development package contains both Pylint and Griffe.
Basic Usage
- Create a Storage object to prepare the data to be stored:
from key_multivalue_storage import Storage # note the module name! my_db = Storage("my_top_level_key", mysubkey="myvalue", myothersk="anotherval") - To store the object, use
Storage.store().my_db.store("database.json") - You can change certain global settings for each
Storageinstance.Storage.indent = 4 #indent size of JSON files Storage.encode = True #Whether to encode stored values Storage.auto_delete_self = True # Whether to automatically release the object # from memory after certain operations i.e. # Storage.store() - Loading a stored object by a top level key and loading all the top level keys of a JSON file:
>>> Storage.Load.by_key("database.json", "my_top_level_key") Storage(top_lv_key="my_top_level_key", key_value_pairs=["mysubkey"="myvalue", "myothersk"="anotherval"]) >>> Storage.Load.keys("database.json") ["my_top_level_key"]
- Editing a subkey’s name and value within the JSON file:
>>> Storage.Edit.propkey("database.json", # file_path "my_top_level_key", # top_lv_key "mysubkey", # oldpropkey "newkey" # newpropkey noexist_ok = True # Creates a new subkey with the new subkey name if the old subkey name did not exist ) ... Storage.Load.values("database.json", "my_top_level_key", keys=True, raw=False) ["newkey: myvalue", "myothersk: anotherval"] >>> Storage.Edit.propval("database.json", # file_path "my_top_level_key", # top_lv_key "myothersk", # propkey "wow!" # newval ) ... Storage.Load.values("database.json", "my_top_level_key", keys=True, raw=False) ["newkey: myvalue", "myothersk: wow!"]
- Deleting a subkey-value pair within the JSON file:
>>> Storage.Delete.by_propkey("database.json", # file_path "my_top_level_key", # top_level_key "myothersk" # property_key ) ... Storage.Load.values("database.json", "my_top_level_key", keys=True, raw=False) ["newkey: myvalue"]
- Adding and subtracting two
Storageinstances:>>> # Adding instances combines the two instances, as long as the top level key is the same. ... addStorage = Storage("combine", sk1="val1") + Storage("combine", sk2="val2") ... print(addStorage) Storage(top_lv_key="combine", key_value_pairs=["sk1"="val1", "sk2"="val2"]) >>> # Subtracting instances remove any exact same key-value pairs from the two instances, as long as the top level key is the same. ... subStorage = Storage("combine", sk1="val1", sk2="val2") - Storage("combine", sk2="val2") ... print(addStorage) Storage(top_lv_key="combine", key_value_pairs=["sk1"="val1"])
Tip
All kms features are documented in the documentation.