Skip to main content

One interface, multiple file formats — async nested storage with dot-path access and atomic writes

Project description

nestio

Async local storage for Python. One interface, multiple file formats.

Stop writing the same boilerplate every time you need local storage.

nestio provides a consistent async API for JSON, TOML, YAML, TOON, and MessagePack — plus a typed .env loader — with:

  • Dot-path access"user.settings.theme"
  • Atomic writes — never leave files half-written
  • Automatic locking — safe concurrent writes out of the box
  • One API across every supported format

Supported formats: JSON • TOML • YAML • TOON • MessagePack

Same API. Same code. Different format.


Why nestio?

Without nestio:

import json

with open("config.json", "r") as f:
    data = json.load(f)

data["user"]["settings"]["theme"] = "dark"

with open("config.json", "w") as f:
    json.dump(data, f, indent=4)

With nestio:

from nestio.files import JSON

db = JSON("config.json")
await db.set("user.settings.theme", "dark")

Same logic. Less boilerplate.


Installation

pip install nestio

PyPI Version Python 3.9+ License MIT


Features

Feature Supported
Async API
Dot-path access
Atomic writes
Automatic locking
JSON
TOML
YAML
MessagePack
TOON
.env loader

Supported formats

Format Class File ext Best for
JSON JSON .json General purpose, APIs, configs
TOML TOML .toml Configuration files
YAML YAML .yaml Human-friendly configs
TOON TOON .toon LLM input — compact, token-efficient
MessagePack MSGPACK .msgpack Binary, fast, compact serialization

Quickstart

File storage

import asyncio
from nestio.files import JSON  # swap for TOML, YAML, TOON, or MSGPACK — API is identical

async def main():
    db = JSON("data/config.json")

    await db.set("user.name", "Alice")
    await db.set("user.settings.theme", "dark")
    await db.set("user.scores", [])

    name  = await db.get("user.name")            # "Alice"
    theme = await db.get("user.settings.theme")  # "dark"

    await db.append("user.scores", 42)
    await db.update("user.settings", {"language": "en"})
    await db.delete("user.settings.theme")

asyncio.run(main())

TOML

from nestio.files import TOML

cfg = TOML("data/config.toml")
await cfg.set("server.host", "localhost")
await cfg.set("server.port", 8080)
await cfg.update("server", {"debug": True})

YAML

from nestio.files import YAML

cfg = YAML("data/config.yaml")
await cfg.set("server.host", "localhost")
await cfg.set("tags", ["web", "api"])
await cfg.append("tags", "async")

MessagePack

from nestio.files import MSGPACK

cache = MSGPACK("data/cache.msgpack")
await cache.set("session.user_id", 1234)
await cache.set("session.permissions", ["read", "write"])
await cache.append("session.permissions", "admin")

TOON

from nestio.files import TOON

store = TOON("data/context.toon")
await store.set("context.task", "Our favorite hikes")
await store.set("friends", ["ana", "luis", "sam"])
await store.update("context", {"season": "spring_2025"})

Environment variables

nestio.env gives you a typed wrapper around your .env file — no more scattered os.getenv() calls.

from nestio.env import Env

env = Env(".env")  # raises FileNotFoundError if missing

# Basic access
debug = env.get("DEBUG", default="false")
host  = env["HOST"]          # same as os.getenv("HOST")

# Typed getters
port    = env.get_int("PORT")        # int
ratio   = env.get_float("RATIO")     # float
verbose = env.get_bool("VERBOSE")    # True for "true", "1", "yes", "y", "t"
tags    = env.get_list("TAGS")       # splits on "," by default
tags    = env.get_list("TAGS", sep=" ")  # custom separator

# Required variables — raises KeyError if missing or empty
secret  = env.require("SECRET_KEY")

Given a .env file like:

HOST=localhost
PORT=8080
DEBUG=true
TAGS=web,api,async
SECRET_KEY=supersecret

File storage API

All five methods work the same across every format. All are async and must be awaited.

Import from the submodule or the top level — both work:

from nestio.files import JSON   # explicit
from nestio import JSON         # shortcut

get(path, default=None)

Returns the value at the dot-path, or default if it doesn't exist.

value = await db.get("server.host", default="localhost")

set(path, value)

Sets the value at the dot-path. Creates intermediate dicts as needed.

await db.set("server.port", 8080)

delete(path)

Removes the key at the dot-path. Does nothing if the key doesn't exist.

await db.delete("server.port")

append(path, value)

Appends a value to a list at the dot-path. Creates the list if it doesn't exist yet.

await db.append("logs", {"level": "info", "msg": "started"})

update(path, new_data)

Deep-merges a dict into the value at the dot-path. Existing keys not in new_data are preserved.

await db.update("config", {"retries": 3, "timeout": 30})

How it works

  • Dot-path access — keys like "a.b.c" resolve through nested dicts automatically.
  • Atomic writes — every save writes to a temp file first, then uses os.replace() to swap it in. Your file is never half-written.
  • Per-key locking — concurrent writes to the same path are serialized with asyncio.Lock, while independent paths write in parallel. Locks clean up automatically after a TTL.

Format-specific notes

TOON

TOON (Token-Oriented Object Notation) is a compact, human-readable format designed for LLM input. It combines YAML-style indentation for nested objects with CSV-style rows for uniform arrays — achieving up to 40% fewer tokens than JSON while maintaining full round-trip fidelity.

A .toon file produced by nestio looks like this:

context:
  task: Our favorite hikes
  season: spring_2025
friends[3]: ana,luis,sam
hikes[3]{id,name,distanceKm,wasSunny}:
  1,Blue Lake Trail,7.5,true
  2,Ridge Overlook,9.2,false
  3,Wildflower Loop,5.1,true

MessagePack

MessagePack is a binary format — files are not human-readable, but they're smaller and faster to parse than any text-based format. Best for local caches and high-frequency storage where you don't need to inspect files manually.


Roadmap

  • JSON support
  • TOML support
  • YAML support
  • MessagePack support
  • TOON support
  • Atomic writes
  • Async locking
  • .env loader
  • Benchmarks
  • Automatic format detection
  • More examples

Why I built nestio

I found myself repeatedly writing the same file handling code in async projects:

  • Load a file
  • Navigate nested dictionaries
  • Modify values
  • Save safely
  • Handle concurrent writes

nestio was created to remove that boilerplate and provide a consistent interface across multiple storage formats.


Requirements


License

MIT © MrBaconHat

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nestio-0.2.6.tar.gz (12.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nestio-0.2.6-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

File details

Details for the file nestio-0.2.6.tar.gz.

File metadata

  • Download URL: nestio-0.2.6.tar.gz
  • Upload date:
  • Size: 12.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for nestio-0.2.6.tar.gz
Algorithm Hash digest
SHA256 06de38b33c58322188b120ace511dca5e329bc56c6f739e9326f6ec27efd3f11
MD5 3d8e74aebb3b8b9e58faf0d55556e58c
BLAKE2b-256 a2362ec7c56c7019df788dfddb0f4d220c1fa74b59b81a9b162be752a8138fde

See more details on using hashes here.

File details

Details for the file nestio-0.2.6-py3-none-any.whl.

File metadata

  • Download URL: nestio-0.2.6-py3-none-any.whl
  • Upload date:
  • Size: 11.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for nestio-0.2.6-py3-none-any.whl
Algorithm Hash digest
SHA256 956aa10d682cc0e3c76cc05f92bd5c56d697c1fa4591763d271fe6289844dd32
MD5 677812af32b25d53e4692d05d20c4435
BLAKE2b-256 8df7a12030480d217fac2e19532d959fc159752482ce3635abe18642314ae336

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page