A lightweight, file-based NoSQL database for Python with MongoDB-like interface and optional encryption support.
- Document-Oriented: Store and query data as flexible JSON documents
- File-Based: No server setup required, data stored in JSON files
- Encryption Support: Optional Fernet encryption for sensitive data
- MongoDB-like API: Familiar interface with collections and documents
- Thread-Safe: Built-in thread safety with RLock
- Cursor Support: Advanced querying with sorting, limiting, and pagination
- Singleton Pattern: Efficient connection management per database
- Pure Python: Built with Python 3.8+ and standard type hints
# Basic installation
pip install pantherdb
# With encryption support
pip install pantherdb[full]from pantherdb import PantherDB
# Create a database
db = PantherDB('my_database')
# Get a collection
users = db.collection('users')
# Insert a document
user = users.insert_one(
name='John Doe',
email='john@example.com',
age=30,
is_active=True
)
# Find documents
john = users.find_one(name='John Doe')
all_users = users.find()
active_users = users.find(is_active=True)
# Update a document
john.update(age=31)
# Delete a document
john.delete()from pantherdb import PantherDB
# Basic database (creates database.json)
db = PantherDB('my_app')
# Encrypted database (creates database.pdb)
from cryptography.fernet import Fernet
key = Fernet.generate_key() # Store this key securely!
db = PantherDB('secure_app', secret_key=key)
# Return raw dictionaries instead of PantherDocument objects
db = PantherDB('my_app', return_dict=True)
# Return Cursor objects for find operations
db = PantherDB('my_app', return_cursor=True)# Access a collection
users = db.collection('users')
# Delete a collection and all its documents
users.drop()# Insert a single document
user = users.insert_one(
name='Alice',
email='alice@example.com',
age=25,
tags=['python', 'developer']
)
# Documents automatically get a unique _id field
print(user.id) # ULID string# Find one document
user = users.find_one(name='Alice')
user = users.find_one() # Get first document
# Find first document (alias)
user = users.first(name='Alice')
user = users.first() # Get first document
# Find last document
user = users.last(name='Alice')
user = users.last() # Get last document
# Find multiple documents
all_users = users.find()
alice_users = users.find(name='Alice')
# Count documents
total_users = users.count()
alice_count = users.count(name='Alice')# Update a specific document
user = users.find_one(name='Alice')
user.update(age=26, email='alice.new@example.com')
# Update with filter
updated = users.update_one(
{'name': 'Alice'},
age=26,
email='alice.new@example.com'
)
# Update multiple documents
updated_count = users.update_many(
{'age': 25},
age=26
)# Delete a specific document
user = users.find_one(name='Alice')
user.delete()
# Delete with filter
deleted = users.delete_one(name='Alice')
# Delete multiple documents
deleted_count = users.delete_many(age=25)user = users.find_one(name='Alice')
# Access fields as attributes
print(user.name) # 'Alice'
print(user.age) # 25
print(user.email) # 'alice@example.com'
# Access fields as dictionary items
print(user['name']) # 'Alice'
print(user['age']) # 25
# Get document ID
print(user.id) # ULID stringuser = users.find_one(name='Alice')
# Set fields directly
user.age = 26
user.status = 'active'
user.save() # Save changes to database
# Update multiple fields
user.update(
age=26,
status='active',
last_login='2023-01-01'
)
# Get JSON representation
json_data = user.json()
print(json_data) # '{"_id": "...", "name": "Alice", "age": 26}'When using return_cursor=True, find operations return Cursor objects with advanced features:
# Enable cursor mode
db = PantherDB('my_app', return_cursor=True)
users = db.collection('users')
# Basic cursor iteration
cursor = users.find()
for user in cursor:
print(user.name)
# Sorting
cursor = users.find().sort('age', -1) # Descending by age
cursor = users.find().sort('name', 1) # Ascending by name
# Limiting and skipping
cursor = users.find().limit(10).skip(5) # Pagination
# Chaining operations
cursor = users.find(age=18).sort('age', -1).limit(5)
# Async iteration
async for user in cursor:
print(user.name)For sensitive data, PantherDB supports database encryption:
from pantherdb import PantherDB
from cryptography.fernet import Fernet
# Generate a key (store this securely!)
key = Fernet.generate_key()
# Create encrypted database
db = PantherDB('secure_database', secret_key=key)
# All operations work the same way
users = db.collection('users')
user = users.insert_one(name='Secret User', password='hashed_password')Important Notes:
- Store your encryption key securely
- Don't generate a new key on every run
- Losing the key means losing access to your data
- Encrypted databases use
.pdbextension, unencrypted use.json
PantherDB implements a singleton pattern per database file:
# Multiple instances with same name share data
db1 = PantherDB('my_app')
db2 = PantherDB('my_app')
# Both instances point to the same database
users1 = db1.collection('users')
users2 = db2.collection('users')
# Changes in one instance are visible in the other
users1.insert_one(name='Alice')
user = users2.find_one(name='Alice') # Found!All operations are thread-safe:
import threading
def insert_user(name):
db = PantherDB('my_app')
users = db.collection('users')
users.insert_one(name=name)
# Safe to use from multiple threads
threads = [
threading.Thread(target=insert_user, args=(f'User{i}',))
for i in range(10)
]
for thread in threads:
thread.start()
for thread in threads:
thread.join()db = PantherDB('my_app')
# String representation shows collections and document counts
print(db)
# PantherDB(
# users: 5 documents,
# posts: 10 documents
# )
# Collection information
users = db.collection('users')
print(users)
# PantherCollection(
# collection_name: users
# name: str
# age: int
# email: str
# )PantherDB raises PantherDBException for database errors:
from pantherdb import PantherDB, PantherDBException
try:
db = PantherDB('corrupted_db', secret_key=wrong_key)
except PantherDBException as e:
print(f"Database error: {e}")This project is licensed under the MIT License - see the LICENSE file for details.
If you find Panther useful, please give it a star! ⭐️