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.5.tar.gz (13.0 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.5-py3-none-any.whl (12.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: nestio-0.2.5.tar.gz
  • Upload date:
  • Size: 13.0 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.5.tar.gz
Algorithm Hash digest
SHA256 e43f45c0a5f6dd0886a42a3463d96da0710825e672f0bae2ab33b0484f59a8bf
MD5 37e08a925a5b51e30fca89fa672c21bf
BLAKE2b-256 e3d57f5806925071bccc7111acb0f126e9e69340a1112685af768b389c182e54

See more details on using hashes here.

File details

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

File metadata

  • Download URL: nestio-0.2.5-py3-none-any.whl
  • Upload date:
  • Size: 12.4 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.5-py3-none-any.whl
Algorithm Hash digest
SHA256 48a5b7097e89bad2ac6393951f35d65f7e29e31827929ed660d6ef6adaee59d4
MD5 a7089557d52d9b80ac970da8fe797e23
BLAKE2b-256 631a72fa3379d201404632453a79e1f6093d1be7f7c5286bc0463c39e6820de7

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