Universal auto-number generator by Risna Berti (Nanumber)
Project description
📦 Risnaberti Nanumber
Universal auto-number generator library by Risna Berti (Nana)
Aman, fleksibel, dan mudah diintegrasikan ke FastAPI, Django, Flask, atau framework lainnya.
✨ Fitur Utama
✅ Format fleksibel: #SUP-{y}{number} → #SUP-250001
✅ Reset otomatis per tahun / bulan
✅ Thread-safe (aman dari race condition)
✅ Multi-storage (Memory, SQLite, PostgreSQL, MySQL)
✅ Siap integrasi ke FastAPI / Django
✅ Terinspirasi dari Laravel Nanamber
🧱 Instalasi
pip install risnaberti-nanumber
⚙️ Quick Start (Demo Mode)
🧩 Gunakan
MemoryStorageuntuk testing atau eksplorasi awal.
Data hanya disimpan sementara di RAM — akan hilang setelah program dihentikan.
from risnaberti.nanumber import NumberGenerator, MemoryStorage
# Gunakan penyimpanan in-memory (sementara)
storage = MemoryStorage()
gen = NumberGenerator(storage)
print(gen.generate("supplier", "#SUP-{y}{number}"))
# 👉 #SUP-250001
Cocok untuk demo atau unit test, bukan untuk produksi.
💾 Production Mode (Persistent Storage)
💾 Gunakan
SQLAlchemyStorageuntuk penyimpanan permanen di database.
Nanumber akan otomatis membuat tabelauto_numbersuntuk menyimpanlast_value.
from risnaberti.nanumber import NumberGenerator, SQLAlchemyStorage
# Gunakan SQLite (atau PostgreSQL/MySQL)
storage = SQLAlchemyStorage("sqlite:///nanumber.db")
gen = NumberGenerator(storage)
print(gen.generate("invoice", "INV-{Y}-{number:04d}"))
# 👉 INV-2025-0001
Setelah restart aplikasi, nomor akan berlanjut dari nilai terakhir di tabel database.
⚙️ Integrasi dengan FastAPI
1️⃣ Instal dependency
pip install fastapi[all] risnaberti-nanumber
2️⃣ Tambahkan endpoint
# app/main.py
from fastapi import FastAPI
from risnaberti.nanumber import NumberGenerator, SQLAlchemyStorage
app = FastAPI()
storage = SQLAlchemyStorage("sqlite:///nanumber.db")
gen = NumberGenerator(storage)
@app.get("/generate/{entity}")
def generate_number(entity: str):
format_map = {
"supplier": "#SUP-{y}{number:04d}",
"invoice": "INV-{Y}-{number:05d}",
}
fmt = format_map.get(entity, "{Y}{number:04d}")
return {"entity": entity, "number": gen.generate(entity, fmt)}
3️⃣ Jalankan server
uvicorn app.main:app --reload
Buka:
🧩 Integrasi dengan Django
# apps/supplier/signals.py
from django.db.models.signals import pre_save
from django.dispatch import receiver
from .models import Supplier
from risnaberti.nanumber import NumberGenerator, SQLAlchemyStorage
storage = SQLAlchemyStorage("sqlite:///db.sqlite3")
gen = NumberGenerator(storage)
@receiver(pre_save, sender=Supplier)
def generate_supplier_code(sender, instance, **kwargs):
if not instance.code:
instance.code = gen.generate("supplier", "#SUP-{y}{number}")
🔢 Contoh Format Nomor
| Template | Hasil | Keterangan |
|---|---|---|
#SUP-{y}{number} |
#SUP-250001 |
Tahun 2 digit |
INV-{Y}-{number:05d} |
INV-2025-00001 |
Tahun penuh + padding |
{m}{number:03d} |
11001 |
Reset otomatis tiap tahun |
🧠 Uji Multi-thread (Concurrency Test)
import threading
from risnaberti.nanumber import NumberGenerator, SQLAlchemyStorage
storage = SQLAlchemyStorage("sqlite:///test.db")
gen = NumberGenerator(storage)
def worker():
print(gen.generate("supplier", "#SUP-{y}{number:04d}"))
threads = [threading.Thread(target=worker) for _ in range(10)]
for t in threads: t.start()
for t in threads: t.join()
Output:
#SUP-250001
#SUP-250002
#SUP-250003
...
Semua hasil unik — tidak ada duplikasi walaupun 10 thread berjalan bersamaan 🚀
📁 Struktur Package
risnaberti/
nanumber/
├── core.py
├── exceptions.py
├── config.py
└── storage/
├── base.py
├── memory.py
├── sqlite.py
└── sqlalchemy_storage.py
📄 Lisensi
MIT © 2025 Risna Berti
💬 Kontribusi
Pull request selalu terbuka 🎉
Jika kamu menemukan bug atau ide fitur baru, silakan buat issue di GitHub:
👉 https://github.com/risnaberti/nanumber
🌟 Dukungan & Kontak
Jika kamu menggunakan library ini di project kamu, kasih bintang di GitHub ⭐
📧 Email: risnaberti07@gmail.com 🐙 GitHub: @risnaberti
✨ Made with ❤️ by Risna Berti
"Because numbering should be smart, safe, and beautiful."
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 risnaberti_nanumber-0.1.1.tar.gz.
File metadata
- Download URL: risnaberti_nanumber-0.1.1.tar.gz
- Upload date:
- Size: 10.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
85ac1f8cc689e240294b8789ff09072bae8c54107c9e40ef05274a5e339f1b3a
|
|
| MD5 |
03d36a8f4ca924202ab8348346f94c17
|
|
| BLAKE2b-256 |
df5b8a790370ddef7066c3ce25f1b64011d6cbb1125fd52bf598f7a9d6d2fcb1
|
File details
Details for the file risnaberti_nanumber-0.1.1-py3-none-any.whl.
File metadata
- Download URL: risnaberti_nanumber-0.1.1-py3-none-any.whl
- Upload date:
- Size: 8.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
949042de02f7546ab748c1cd401a7168b2b95a6f75359eee0a35283ae0fb8103
|
|
| MD5 |
a380a9a39ee565a57839f80fb29d99bb
|
|
| BLAKE2b-256 |
5062fd6d0fd99387173734b1c6719a0c4edd10dc0d1eee6e54368bf7073f11ef
|