coodie = cassandra+beanie(hoodie)
Project description
coodie
The modern Pydantic-based ODM for Cassandra & ScyllaDB
Cassandra + Beanie (hoodie) = coodie ๐งฅ
๐ Documentation โข ๐ Quick Start โข ๐ค Contributing โข ๐ Changelog
Define your data models as Python classes, and coodie handles schema synchronization, serialization, and query building โ with both sync and async APIs.
โจ Feature Highlights
|
๐งฌ Pydantic v2 Models โ full type-checking & validation |
๐ Automatic Schema Sync โ |
๐ How Does coodie Compare?
| Feature | coodie | beanie | cqlengine |
|---|---|---|---|
| Database | Cassandra / ScyllaDB | MongoDB | Cassandra |
| Schema Definition | Pydantic v2 BaseModel |
Pydantic v2 BaseModel |
Custom columns.* classes |
| Type Hints | โ
Native Annotated[] |
โ Native Pydantic | โ No type hints |
| Async Support | โ First-class | โ First-class | โ Sync only |
| Sync Support | โ
coodie.sync |
โ Async only | โ Sync only |
| Query API | Chainable QuerySet |
Chainable FindMany |
Chainable QuerySet |
| Schema Migration | โ
sync_table() |
โ Manual | โ
sync_table() |
| LWT (Compare-and-Set) | โ
if_not_exists() |
N/A | โ
iff() |
| Batch Operations | โ
BatchQuery |
โ | โ
BatchQuery |
| Counter Columns | โ
Counter() |
โ | โ
columns.Counter |
| User-Defined Types | โ
UserType |
โ | โ
UserType |
| TTL Support | โ Per-save TTL | โ | โ Per-save TTL |
| Pagination | โ
Token-based PagedResult |
โ Cursor-based | โ Manual |
| Multiple Drivers | โ 3 drivers | motor only | cassandra-driver only |
| Polymorphic Models | โ
Discriminator |
โ | โ |
| Python Version | 3.10+ | 3.8+ | 3.6+ |
๐ฆ Installation
pip install coodie
Choose a driver extra for your cluster:
pip install "coodie[scylla]" # ScyllaDB / Cassandra (recommended)
pip install "coodie[cassandra]" # Cassandra via cassandra-driver
pip install "coodie[acsylla]" # Async-native via acsylla
๐ Quick Start
1. Start a local ScyllaDB (or use an existing cluster):
docker run --name scylla -d -p 9042:9042 scylladb/scylla --smp 1
# Wait for it to be ready (~30s), then create a keyspace
docker exec -it scylla cqlsh -e \
"CREATE KEYSPACE IF NOT EXISTS my_ks
WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};"
2. Install coodie:
pip install "coodie[scylla]"
3. Write your first script:
from coodie.sync import Document, init_coodie
from coodie.fields import PrimaryKey
from pydantic import Field
from typing import Annotated
from uuid import UUID, uuid4
# Connect
init_coodie(hosts=["127.0.0.1"], keyspace="my_ks")
# Define a model
class User(Document):
id: Annotated[UUID, PrimaryKey()] = Field(default_factory=uuid4)
name: str
email: str
class Settings:
name = "users"
# Sync schema & insert
User.sync_table()
user = User(name="Alice", email="alice@example.com")
user.save()
# Query
print(User.find(name="Alice").allow_filtering().all())
๐ก Async? Just swap
coodie.syncforcoodie.aioand addawaitโ that's it!
๐ Usage
Define a Document
from typing import Annotated
from uuid import UUID, uuid4
from pydantic import Field
from coodie import Document, PrimaryKey, ClusteringKey, Indexed
class Product(Document):
id: Annotated[UUID, PrimaryKey()] = Field(default_factory=uuid4)
category: Annotated[str, ClusteringKey()] = "general"
name: str
brand: Annotated[str, Indexed()] = "Unknown"
price: float = 0.0
class Settings:
name = "products" # table name (defaults to snake_case class name)
keyspace = "my_ks"
Async API โ coodie / coodie.aio
import asyncio
from coodie import init_coodie
# Product defined above โ same field definitions, using coodie.aio.Document
async def main():
await init_coodie(hosts=["127.0.0.1"], keyspace="my_ks")
await Product.sync_table()
p = Product(name="Gadget", brand="Acme", price=9.99)
await p.save()
results = await Product.find(brand="Acme").limit(10).all()
for product in results:
print(product.name, product.price)
gadget = await Product.get(id=p.id)
await gadget.delete()
asyncio.run(main())
Sync API โ coodie.sync
from coodie.sync import Document, init_coodie
class Product(Document):
... # same field definitions
init_coodie(hosts=["127.0.0.1"], keyspace="my_ks")
Product.sync_table()
p = Product(name="Widget", price=4.99)
p.save()
results = Product.find(brand="Acme").allow_filtering().all()
one = Product.find_one(name="Widget")
QuerySet Chaining
# Filter, sort, and limit
products = (
await Product.find()
.filter(brand="Acme")
.order_by("price")
.limit(20)
.all()
)
# Count
n = await Product.find(brand="Acme").allow_filtering().count()
# Async iteration
async for p in Product.find(brand="Acme"):
print(p)
# Delete matching rows
await Product.find(brand="Discontinued").allow_filtering().delete()
Field Annotations Reference
| Annotation | Purpose |
|---|---|
PrimaryKey(partition_key_index=0) |
Partition key column (composite keys via index) |
ClusteringKey(order="ASC", clustering_key_index=0) |
Clustering column |
Indexed(index_name=None) |
Secondary index |
Counter() |
Counter column |
Discriminator() |
Polymorphic model discriminator |
๐ Learn More
| Resource | Link |
|---|---|
| ๐ Full Documentation | scylladb.github.io/coodie |
| ๐ Quick Start Guide | Installation & Quickstart |
| ๐ Benchmark History | Performance Trends |
| ๐ Migrating from cqlengine | Migration Guide |
| ๐ค Contributing | CONTRIBUTING.md |
| ๐ Changelog | CHANGELOG.md |
| ๐ Bug Reports | GitHub Issues |
Contributors โจ
Thanks goes to these wonderful people (emoji key):
Israel Fruchter ๐ป ๐ค ๐ |
This project follows the all-contributors specification. Contributions of any kind welcome!
Credits
This package was created with Cookiecutter and the browniebroke/cookiecutter-pypackage project template.
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 coodie-1.0.1.tar.gz.
File metadata
- Download URL: coodie-1.0.1.tar.gz
- Upload date:
- Size: 3.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8921fd3fe877f0b01ed90c1fac1c72e128099acfaa556ea7377944cef9f55e3e
|
|
| MD5 |
e425d686653b84b19bac8379c7bd2d5e
|
|
| BLAKE2b-256 |
3090f7fe013d1f79c1eed420cc90d5c2a7d0cf5d5f7dc89157f3cf1b55d649cc
|
Provenance
The following attestation bundles were made for coodie-1.0.1.tar.gz:
Publisher:
ci.yml on scylladb/coodie
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
coodie-1.0.1.tar.gz -
Subject digest:
8921fd3fe877f0b01ed90c1fac1c72e128099acfaa556ea7377944cef9f55e3e - Sigstore transparency entry: 1293702155
- Sigstore integration time:
-
Permalink:
scylladb/coodie@ca54eca21e2bac1ad4e5625b8503a86add559ed6 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/scylladb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@ca54eca21e2bac1ad4e5625b8503a86add559ed6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file coodie-1.0.1-py3-none-any.whl.
File metadata
- Download URL: coodie-1.0.1-py3-none-any.whl
- Upload date:
- Size: 76.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d4f3257173dd0ed76dde2aba24fbef085d4a6f7cae7826a3f59319318d5df91
|
|
| MD5 |
89e43da450103ba6895cd750fbaf09b6
|
|
| BLAKE2b-256 |
cfdf5e2478a7e109b7578e9282948951fd16c06794a6482f669f0c3a93a3a7b2
|
Provenance
The following attestation bundles were made for coodie-1.0.1-py3-none-any.whl:
Publisher:
ci.yml on scylladb/coodie
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
coodie-1.0.1-py3-none-any.whl -
Subject digest:
4d4f3257173dd0ed76dde2aba24fbef085d4a6f7cae7826a3f59319318d5df91 - Sigstore transparency entry: 1293702171
- Sigstore integration time:
-
Permalink:
scylladb/coodie@ca54eca21e2bac1ad4e5625b8503a86add559ed6 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/scylladb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@ca54eca21e2bac1ad4e5625b8503a86add559ed6 -
Trigger Event:
push
-
Statement type: