Skip to main content

Async TCP in-memory datastore with secure client-server protocol, supporting real-time multi-client CRUD operations.

Project description

Nemoria

PyPI version Python Versions License: MIT

Nemoria is a lightweight, asynchronous, in-memory datastore with secure client-server protocol, supporting real-time multi-client CRUD operations.

With Nemoria, you can read and write data in real time from any process, thread, or program, using multiple clients simultaneously.

✨ Think of it as a tiny Redis-like system built entirely in Python.


Features

  • 🚀 Asynchronous I/O powered by asyncio
  • 🔑 Password-based authentication
  • 🧩 Nested routes with hierarchical Route objects
  • Simple CRUD API (get, all, set, delete, drop, purge, save, ping)
  • 🔄 Multi-client access – read and write data in real time across any process, thread, or external program
  • 🛠 Minimalistic & extensible design for custom protocols

Installation

A) Install from PyPI

pip install nemoria -U

B) Local source install

git clone https://github.com/moh-dehghan/nemoria.git
cd nemoria
pip install -e .

Verification

Check if the package is installed correctly:

python -c "import nemoria; print(nemoria.__version__)"

Quick Start

1. Run the Server

# server.py
import asyncio
from nemoria import Server

async def main():
    server = Server(
        host="localhost",
        port=1234,
        namespace="Nemoria",
        password="12345678",
    )

    # Run server
    await server.run_forever(raise_on_error=False)

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        pass

Run it in one terminal:

python server.py

2. Connect a Client

# client.py
import asyncio
from nemoria import Client, Route
# Also you can import Route from pyroute module -> from pyroute import Route

async def main():
    client = Client(host="localhost", port=1234, password="12345678")
    
    # Connect
    if not await client.connect():
        return

    # Create data
    await client.set(route=Route("user", "profile", "name"), value="Alice")
    await client.set(route=Route("user", "profile", "age"), value=30)
    await client.save(codec="json", path="config.json", threadsafe=True)

    # Read data
    print(await client.get(route=Route("user", "profile", "name")))  # -> "Alice"
    print(await client.all())  # -> {'user': {'profile': {'name': 'Alice', 'age': 30}}}

    # Update data
    await client.set(
        route=Route("user", "profile", "age"),
        value=31,
        save_on_disk=True,
        codec="json",
        path="config.json",
        threadsafe=True,
    )  # -> 31
    print(await client.all())

    # Delete part of a route
    await client.delete(
        route=Route("user", "profile", "age"),
        save_on_disk=True,
        codec="json",
        path="config.json",
        threadsafe=True,
    )
    print(await client.all())

    # Drop the entire top-level route
    await client.drop(route=Route("user"))
    print(await client.all())  # -> {}

    await asyncio.Future()


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        pass

Run it in another terminal:

python client.py

More Examples

Storing Nested Data

await client.set(route=Route("blog", "posts", "1", "title"), value="Hello World")
await client.set(route=Route("blog", "posts", "1", "tags"), value=["intro", "nemoria"])
await client.set(route=Route("blog", "posts", "2", "title"), value="Async Rocks")

print(await client.all())
# {
#   "blog": {
#     "posts": {
#       "1": {"title": "Hello World", "tags": ["intro", "nemoria"]},
#       "2": {"title": "Async Rocks"}
#     }
#   }
# }

Deleting & Dropping & Purging & Saving

# Delete just one nested field
await client.delete(route=Route("blog", "posts", "1", "tags"))

# Drop entire "posts" subtree
await client.drop(route=Route("blog", "posts"))

# Clear entire datastore
await client.purge()

# Save on disk
await client.save(codec="yaml", path="config.yaml", threadsafe=True)

Ping & Healthcheck

# Ping
print(await client.ping()) # -> Latency in milliseconds, or `None` on timeout/connection error.

# Healthcheck
print(await client.is_alive()) # -> True or False

Close Client & Shutdown Server

# Close Client
await client.close()

# Shutdown Server
await client.shutdown()

Development Notes

Nemoria is intentionally designed to be minimalistic yet extensible, with a focus on clarity.

  • 🧩 Architecture:
    The system follows a clear client–server separation.

    • Server: manages connections, authentication, and route-based storage.
    • Client: provides a high-level API for CRUD operations and route traversal.
    • Route: represents nested hierarchical keys for structured data access.
  • ⚙️ Technology Stack:

    • Implemented in Python 3.10+ using asyncio for fully asynchronous I/O.
    • Built around standard Python libraries to keep dependencies minimal.
    • Supports multiple concurrent clients with real-time access guarantees.
  • 🎯 Design Goals:

    • Prioritize readability and hackability over heavy optimizations.
    • Provide a safe playground for learning about async networking and protocol design.
    • Allow easy extension for advanced features like persistence, clustering, and pub/sub.

Roadmap

  • Persistent storage (save/load to disk)
  • Pub/Sub messaging
  • Cluster mode (multi-server)
  • Advanced query language

Educational Use

Nemoria is not only a functional datastore, but also an educational resource.
It is particularly valuable for:

  • 📚 Students & Learners: Understanding how asynchronous servers and clients communicate.
  • 🧑‍💻 Developers: Experimenting with custom protocols, networking, and route-based data models.
  • 🏫 Educators: Demonstrating practical concepts of asyncio, event loops, and concurrency in Python.

License

This project is licensed under the MIT License – see the LICENSE file for details.

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

nemoria-1.1.0.tar.gz (20.0 kB view details)

Uploaded Source

Built Distribution

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

nemoria-1.1.0-py3-none-any.whl (23.9 kB view details)

Uploaded Python 3

File details

Details for the file nemoria-1.1.0.tar.gz.

File metadata

  • Download URL: nemoria-1.1.0.tar.gz
  • Upload date:
  • Size: 20.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for nemoria-1.1.0.tar.gz
Algorithm Hash digest
SHA256 8bf94d27eacd31db98ac8316beadac62af5a980ef381547e07464315a8e3a84b
MD5 f329f876435c7a573e3a4e724fe2f311
BLAKE2b-256 773c6b60d792cfcf6d0328b38d078973d52305c54ec9747cd0e83c415b67b495

See more details on using hashes here.

File details

Details for the file nemoria-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: nemoria-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 23.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for nemoria-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2253ed412322275768e28632c832fdf4a8c8bb5f9491948e8cde3e59ec94721c
MD5 b6b87965b27a7c9503db36f23bfad012
BLAKE2b-256 7249f7d36bede13c7613b41cf688a752f8dbad8a1e5c559ee5c503d8f099e82a

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