Fast JSON-backed persistent dictionary with autosave, TTL, file locking, and namespaced views.
Project description
aiodict
aiodict is a fast, practical, JSON-backed persistent dictionary for Python. It keeps data in memory for speed, flushes to disk atomically, supports TTL, autosave, filesystem locking, transactions, and namespaced views.
It is especially useful for:
- Telegram bots and admin tools
- local config storage
- small to medium automation projects
- prototypes and MVPs
- lightweight caches and counters
It is not a replacement for PostgreSQL or Redis in high-scale distributed systems. It is a strong local persistence layer for one machine, with optional multi-process file coordination via a lock file.
Features
dict-like API- atomic JSON writes using a temporary file and
os.replace - in-memory cache for fast reads and writes
- debounced autosave
- TTL per key
- explicit
flush()andreload() - namespaced views
- transaction-style batching
- backup file creation (
.bak) - filesystem lock for safer multi-process access on one machine
- custom serializer / deserializer hooks
Installation
pip install aiodict
Quick Start
from aiodict import aiodict
# Create or open a JSON-backed store
store = aiodict("db.json")
store["bot_name"] = "My Bot"
store["admin_id"] = 123456789
print(store["bot_name"])
print(store.get("missing", "default value"))
store.flush()
store.close()
Why use aiodict?
aiodict is designed for cases where you want something much more convenient than manually reading and writing JSON, but much simpler than deploying a full database.
Compared to a plain dict, it gives you persistence.
Compared to raw JSON file handling, it gives you:
- better structure
- autosave
- TTL
- locking
- atomic writes
- transactions
- reusable helper methods
Main Class
aiodict
aiodict(
path="db.json",
autosave=True,
autosave_delay=0.35,
create_backup=True,
serializer=None,
deserializer=None,
indent=None,
sort_keys=False,
cleanup_expired_on_load=True,
lock_timeout=10.0,
encoding="utf-8",
)
Parameters
path
Path to the JSON file.
autosave
If True, mutations are automatically flushed after autosave_delay.
autosave_delay
Debounce delay in seconds before a pending write is saved.
create_backup
If True, a .bak copy of the previous JSON file is created before each successful write.
serializer
Optional function used to convert unsupported objects into JSON-serializable values.
deserializer
Optional function used to transform values back after loading from disk.
indent
JSON indentation. Use None for compact output and better speed.
sort_keys
If True, saved JSON keys are sorted.
cleanup_expired_on_load
If True, expired keys are removed when the store is loaded.
lock_timeout
How long to wait for the file lock before raising an error.
encoding
File encoding, usually utf-8.
Basic Usage
Set and read values
from aiodict import aiodict
store = aiodict("db.json")
store["name"] = "Abbosjon"
print(store["name"])
Safe reads
lang = store.get("lang", "en")
Delete a key
del store["name"]
Check if a key exists
if store.exists("name"):
print("exists")
Batch Operations
Update many values
store.update({
"theme": "dark",
"timezone": "Asia/Tashkent",
})
Multi-set
store.mset({
"a": 1,
"b": 2,
"c": 3,
})
Multi-get
values = store.mget(["a", "b", "missing"], default=None)
print(values)
Numeric Helpers
Increment a counter
store.incr("visits")
store.incr("visits", 5)
List Helpers
Append
store.append("admins", 123456789)
Append uniquely
store.append("admins", 123456789, unique=True)
Extend
store.extend("admins", [111, 222, 333])
Remove values from a list
store.remove("admins", 222)
store.remove("admins", 111, all_occurrences=True)
TTL Support
Set with TTL
store.set("otp:123", "918273", ttl=60)
Add or update expiration later
store.expire("otp:123", 120)
Read remaining TTL
remaining = store.ttl("otp:123")
print(remaining)
Remove expiration
store.persist("otp:123")
Remove expired keys manually
removed = store.cleanup_expired()
print(f"Removed {removed} expired keys")
Transactions
Use transaction() when you want several writes and one final flush.
with store.transaction():
store["user:1"] = {"name": "Alice"}
store["user:2"] = {"name": "Bob"}
store.incr("user_count", 2)
This is useful when you want cleaner save behavior and fewer disk writes.
Namespaces
Namespaces help organize keys without managing prefixes manually.
users = store.namespace("users")
settings = store.namespace("settings")
users["1001"] = {"name": "Ali"}
settings["language"] = "uz"
print(users["1001"])
print(settings["language"])
Internally, those become:
users:1001settings:language
Explicit Persistence
Save now
store.flush()
Reload from disk
store.reload()
Close cleanly
store.close()
Context manager usage
from aiodict import aiodict
with aiodict("db.json") as store:
store["hello"] = "world"
Serialization Hooks
Custom serializer
from datetime import datetime
from aiodict import aiodict
def serializer(value):
if isinstance(value, datetime):
return {"__type__": "datetime", "value": value.isoformat()}
raise TypeError
def deserializer(value):
if isinstance(value, dict) and value.get("__type__") == "datetime":
return datetime.fromisoformat(value["value"])
return value
store = aiodict("db.json", serializer=serializer, deserializer=deserializer)
store["created_at"] = datetime.now()
store.flush()
Useful Methods
copy()
Returns a plain dict snapshot of the live data.
snapshot = store.copy()
stats()
Returns basic runtime information.
print(store.stats())
Example output:
{
"keys": 12,
"ttl_keys": 2,
"autosave": True,
"autosave_delay": 0.35,
"file_path": "db.json",
"file_size_bytes": 2048,
"dirty": False,
}
Telegram Bot Example
from aiodict import aiodict
store = aiodict("bot_db.json")
users = store.namespace("users")
stats = store.namespace("stats")
def register_user(user_id: int, full_name: str) -> None:
users[str(user_id)] = {
"full_name": full_name,
"joined_at": "2026-04-05",
}
stats.incr("total_users")
def is_registered(user_id: int) -> bool:
return users.exists(str(user_id))
This works well for small and medium bots on a single machine.
Performance Notes
aiodict is fast because reads and writes primarily hit memory. Disk writes are delayed and batched.
That said, it still writes to one JSON file, so it is best suited for:
- low to moderate write frequency
- one machine
- small to medium datasets
It is not ideal for:
- massive datasets
- very high write concurrency
- distributed multi-server systems
- analytics-heavy workloads
Recommended Use Cases
Good fit:
- bot config
- user settings
- counters
- drafts
- feature flags
- local admin data
- temporary OTP or cooldown keys with TTL
Not a good fit:
- payment ledgers
- large e-commerce systems
- multi-node web backends
- big broadcast job queues at very high scale
Practical Scale Guidance
As a primary store, aiodict is a good fit for:
- a few hundred to a few thousand actively changing keys
- small to medium bots
- local tools and internal systems
For large production systems with many active writes, use PostgreSQL or Redis.
A practical rule:
- Great: small to medium single-machine projects
- Acceptable: moderate workloads with controlled write volume
- Wrong tool: large distributed systems or heavy concurrent write workloads
Development Tips
- call
flush()before shutdown in critical flows - use namespaces to keep keys organized
- prefer compact JSON (
indent=None) for best performance - use
transaction()when doing many writes together - use TTL for temporary values like OTPs and cooldowns
- keep stored values JSON-friendly whenever possible
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aiodict-1.0.1.tar.gz.
File metadata
- Download URL: aiodict-1.0.1.tar.gz
- Upload date:
- Size: 15.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c623d09d38fbbf798af35e735d049e92c7374d2ad3443f0583e86c2833caca1d
|
|
| MD5 |
9c576b3e473879f2fae3d3eb746eb271
|
|
| BLAKE2b-256 |
305dc551c4d5654f06de07d6882cd856ebf5d492683ef670aafaa5066c63e8ff
|
File details
Details for the file aiodict-1.0.1-py3-none-any.whl.
File metadata
- Download URL: aiodict-1.0.1-py3-none-any.whl
- Upload date:
- Size: 10.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
313e5a81d21a9f2a932a948ee869e0542b0cdaa9f06924a9c344d082de9ec83f
|
|
| MD5 |
b5ea787930a2cc89864d6c9eb64e8b44
|
|
| BLAKE2b-256 |
a99fb42cc6745abb36e038951a72f8c6e41ca3e97ca508f10f60399c96de08c3
|