import os
import shutil
import subprocess
import sys
import tempfile
from prollytree import NamespacedKvStore
def setup_example_repo():
tmpdir = tempfile.mkdtemp(prefix="prollytree_ns_example_")
print(f"Created temporary directory: {tmpdir}")
subprocess.run(["git", "init"], cwd=tmpdir, check=True, capture_output=True)
subprocess.run(
["git", "config", "user.name", "Example User"],
cwd=tmpdir,
check=True,
capture_output=True,
)
subprocess.run(
["git", "config", "user.email", "user@example.com"],
cwd=tmpdir,
check=True,
capture_output=True,
)
dataset_dir = os.path.join(tmpdir, "dataset")
os.makedirs(dataset_dir, exist_ok=True)
return tmpdir, dataset_dir
def demo_multiple_namespaces():
print("\nDemo 1: Two namespaces, one store, one commit")
print("=" * 60)
tmpdir, dataset_dir = setup_example_repo()
try:
store = NamespacedKvStore(dataset_dir)
store.ns_insert("users", b"u:alice", b"Alice <alice@example.com>")
store.ns_insert("users", b"u:bob", b"Bob <bob@example.com>")
store.ns_insert("settings", b"theme", b"dark")
store.ns_insert("settings", b"locale", b"en_US")
commit_id = store.commit("seed users + settings")
print(f"Single commit covering both namespaces: {commit_id[:10]}")
print(f"Namespaces in store: {store.list_namespaces()}")
print(f"\nusers/u:alice = {store.ns_get('users', b'u:alice')!r}")
print(f"settings/theme = {store.ns_get('settings', b'theme')!r}")
print(f"\nusers keys: {store.ns_list_keys('users')}")
print(f"settings keys: {store.ns_list_keys('settings')}")
print(f"\nusers root hash: {store.get_namespace_root_hash('users')[:8].hex()}...")
print(f"settings root hash: {store.get_namespace_root_hash('settings')[:8].hex()}...")
finally:
shutil.rmtree(tmpdir, ignore_errors=True)
def demo_branching_per_namespace():
print("\nDemo 2: Branching is store-wide; both namespaces follow")
print("=" * 60)
tmpdir, dataset_dir = setup_example_repo()
try:
store = NamespacedKvStore(dataset_dir)
store.ns_insert("users", b"u:alice", b"Alice")
store.ns_insert("settings", b"theme", b"dark")
store.commit("seed on main")
print(f"main branch seeded; current branch = {store.current_branch}")
store.branch("experiment")
store.ns_insert("users", b"u:carol", b"Carol")
store.ns_insert("settings", b"theme", b"light")
store.commit("experiment: add carol, switch to light theme")
print(f"experiment branch: users = {store.ns_list_keys('users')}")
print(f"experiment branch: theme = {store.ns_get('settings', b'theme')!r}")
store.checkout("main")
print(f"\nback on main; users = {store.ns_list_keys('users')}")
print(f"main branch theme = {store.ns_get('settings', b'theme')!r}")
print(f"main does NOT see u:carol: {store.ns_get('users', b'u:carol')!r}")
finally:
shutil.rmtree(tmpdir, ignore_errors=True)
def demo_isolation_between_namespaces():
print("\nDemo 3: Namespaces are fully isolated")
print("=" * 60)
tmpdir, dataset_dir = setup_example_repo()
try:
store = NamespacedKvStore(dataset_dir)
store.ns_insert("users", b"name", b"Alice")
store.ns_insert("products", b"name", b"Widget")
store.commit("collision-free across namespaces")
print(f"users/name = {store.ns_get('users', b'name')!r}")
print(f"products/name = {store.ns_get('products', b'name')!r}")
print("Each namespace owns its own key space — no collision.")
finally:
shutil.rmtree(tmpdir, ignore_errors=True)
def main():
print("NamespacedKvStore example")
print("=" * 60)
print("Multiple isolated prolly trees in one git-versioned store.")
try:
demo_multiple_namespaces()
demo_branching_per_namespace()
demo_isolation_between_namespaces()
print("\nAll demos completed successfully.")
print("\nKey takeaways:")
print("- One NamespacedKvStore can hold many independent prolly trees.")
print("- ns_insert / ns_get / ns_delete take an extra namespace argument.")
print("- A single commit() lands every dirty namespace atomically.")
print("- branch + checkout flip every namespace at once.")
print("- For text search on a namespace, see text_index_example.py.")
except KeyboardInterrupt:
print("\nExample interrupted by user.")
sys.exit(1)
except Exception as exc: print(f"\nExample failed: {exc}")
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()