Welcome to the key_multivalue_storage wiki!

JSON storage wrapper and editor. Created with love by Boss_1s.

kms logo

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.

CPython

Release
Tests
License

PyPI - Version

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).

(skip to TOC)
(skip to usage)


🚀 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-alpha instead of beta.
  • 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.x branch.
  • 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.

🔗 Full Changelog


🚀 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 with del 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 atpublic metadata/type errors and cleaned up stale storage tests.

⏰ Infrastructure & CI

  • Branch & Deployment Stability: Improved validation for supported semver1.x branches 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.x branch.

Important

Forward-ports from semver1.3.x are not included here. Check the semver1.3.x branch’s README for specific changes there.

🔗 Working Changelog


Documentation

Resources

Contributor Resources

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 Storage instance.
    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 Storage instances:
    >>> # 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.


Thanks for using kms! ❤