A simple, modern, and lightweight Python wrapper for Firebase Auth, Google Cloud Firestore, and Firebase Cloud Storage.
Powered by httpx and Pyrebase4, pyrestore provides a familiar Pyrebase-style fluent path interface (.child().child()) alongside a high-level FirebaseManager client designed for rapid, zero-boilerplate application development.
- High-Level Manager (FirebaseManager): A unified client wrapping Auth, Firestore, and Storage with structured response dictionaries.
- Fluent Path Chaining (pyrestore / Storage): Pyrebase-like path building for low-level database and file manipulation.
- Async & Sync Support: Built-in synchronous methods alongside asynchronous (httpx.AsyncClient) methods for non-blocking UI frameworks (like Flet or FastAPI).
- Automatic Serialization: Seamlessly handles native Python data types (datetime, int, bool, bytes, list, dict).
- Resilient Batch Operations: Multi-collection atomic writes with built-in retry logic and exponential backoff.
- Atomic Field Transforms: Server-side increments and server timestamps with FieldValue.
pip install pyrestore
Note: pyrestore requires Python 3.8+ and will not work with Python 2.
Initialize FirebaseManager for unified access, or use core pyrestore for direct database/storage access.
from pyrestore import FirebaseManager
config = {
"apiKey": "YOUR_API_KEY",
"authDomain": "YOUR_PROJECT.firebaseapp.com",
"projectId": "YOUR_PROJECT_ID",
"storageBucket": "YOUR_PROJECT.appspot.com"
}
fb = FirebaseManager(config)
from pyrestore import pyrestore, Storage
db = pyrestore("YOUR_PROJECT_ID")
storage = Storage(project_id="YOUR_PROJECT_ID", storage_bucket="YOUR_PROJECT.appspot.com")
FirebaseManager automatically updates and synchronizes user tokens with Firestore and Storage under the hood upon login or signup.
# --- LOGIN ---
# Returns a dictionary with a status key, message key, etc
fb.login("user@example.com", "Password123!")
# --- SIGN UP ---
# Validates extra required fields locally before executing network calls
signup_result = fb.signup(
email="jane.doe@example.com",
password="Password123!",
required_fields=["fname", "lname"],
fname="Jane",
lname="Doe"
)
if signup_result["status"] == "success":
print("Account created:", signup_result["user_id"])
import asyncio
loop = asyncio.get_running_loop()
# Execute login off-thread:
result = await loop.run_in_executor(
None,
fb.login,
"user@example.com",
"Password123!"
)
if result.get("status") == "success":
print("User authenticated successfully!")
FirebaseManager automatically manages token sessions, but you can also manually trigger refreshes:
fb.refresh_session(refresh_token)
db.auth(user_id_token)
storage.auth(user_id_token)
Build paths to your documents using standard .child() chaining.
db.child("users").child("user_123")
fb.push_document("products", {"name": "Wireless Mouse", "price": 29.99})
data = {"name": "Wireless Mouse", "price": 29.99}
db.child("products").push(data)
fb.set_document("users", {"name": "Jane Doe", "role": "admin"})
data = {"name": "Jane Doe", "role": "admin"}
db.child("users").child("user_123").set(data)
fb.update_document("users", {"age": 30})
db.child("users").child("user_123").update({"age": 30})
fb.delete_document("users", "user_123")
db.child("users").child("user_123").delete()
Perform atomic writes across single or multiple collections in a single transaction.
fb.batch_update("users", role="admin", age=31)
fb.batch_multi_update(
"set",
users={"user_123": {"name": "Alex"}},
organizations={"org_101": {"name": "Tech Corp"}}
)
fb.batch_multi_update(
users={
"user_123": {"_action": "set", "data": {"name": "Sam", "role": "member"}}
},
orders={
"order_456": {"status": "shipped"} # Defaults to "update"
},
tokens={
"token_789": {"_action": "delete"} # Deletes document
}
)
user_data = fb.get_document("users")
user = db.child("users").child("user_123").get()
all_users = db.child("users").get()
Chain query parameters together on core pyrestore references:
results = (
db.child("products")
.where("rating", ">=", 4)
.order_by("rating", "DESC")
.limit(5)
.get()
)
- where: Supports operators (==, !=, <, <=, >, >=, array-contains, in, array-contains-any).
- order_by: Sort fields in "ASC" or "DESC" order.
- limit: Restrict the number of returned records.
pyrestore provides clean file upload, download, and URL retrieval support with zero boilerplate.
If no filename is provided, upload_file automatically names the file after the logged-in user_id plus the local file extension ({user_id}.png).
# Upload Avatar (Saves as 'avatars/{user_id}.png')
res = fb.upload_file("avatars", "my_photo.png")
if res["status"] == "success":
# Instantly store download URL in Firestore!
fb.update_document("users", {"avatar_url": res["url"]})
# Upload with custom filename
fb.upload_file("receipts", "local_file.pdf", filename="receipt_9921.pdf")
# Get Public File URL
url = fb.get_file_url("receipts", filename="receipt_9921.pdf")
# Download File
fb.download_file("receipts", "downloads/receipt.pdf", filename="receipt_9921.pdf")
# Delete File
fb.delete_file("receipts", filename="receipt_9921.pdf")
Non-blocking operations that prevent UI freezing during file transfers:
# Async Upload
res = await fb.upload_file_async("avatars", "my_photo.png")
# Async Download
await fb.download_file_async("receipts", "downloads/receipt.pdf", filename="receipt_9921.pdf")
Access storage directly using Pyrebase-style chainable paths.
# Upload
fb.storage.child("avatars").child("user_123.png").put("path/to/local.png")
# Get Download URL
url = fb.storage.child("avatars").child("user_123.png").get_url()
# Download
fb.storage.child("avatars").child("user_123.png").download("saved.png")
# Delete
fb.storage.child("avatars").child("user_123.png").delete()
# Async Upload
await fb.storage.child("avatars").child("user_123.png").put_async("path/to/local.png")
# Async Get Download URL
url = await fb.storage.child("avatars").child("user_123.png").get_url_async()
# Async Download
await fb.storage.child("avatars").child("user_123.png").download_async("saved.png")
# Async Delete
await fb.storage.child("avatars").child("user_123.png").delete_async()
from pyrestore import FieldValue
db.child("products").child("product_123").update({
"view_count": FieldValue.increment(1),
"updatedAt": FieldValue.server_timestamp()
})
from pyrestore import RuleBuilder
fs_rules = RuleBuilder("firestore")
# Users can only read/write their own profile
fs_rules.allow_owner_only("users/{userId}")
# Public products catalog, but only logged-in users can add products
fs_rules.allow_public("products/{productId}", read=True, write=False)
# Export to firestore.rules
fs_rules.export()
storage_rules = RuleBuilder("storage")
# User avatars can only be modified by the profile owner
storage_rules.allow_owner_only("avatars/{userId}.png")
# Export to storage.rules
storage_rules.export()
# Add a custom helper function to check admin status
builder.add_function(
name="isAdmin",
params=[],
expression="request.auth != null && request.auth.token.admin == true"
)
- See
RULEBUILDER_CHEATSHEET.mdfor more examples
This project is licensed under the MIT License.