Skip to main content

Python bindings for ScyllaDB/Cassandra using scylla-rust-driver

Project description

rsylla

High-performance Python bindings for ScyllaDB/Cassandra using the official scylla-rust-driver.

Features

  • High Performance: Built on top of the official Rust driver for ScyllaDB
  • Full API Coverage: Every function/method from the Rust driver has a Python equivalent
  • Type Hints: Complete type annotations for better IDE support
  • Async Runtime: Efficient async operations handled by Tokio runtime
  • Easy to Use: Pythonic API that feels natural

Installation

pip install rsylla

Building from source

You'll need Rust and maturin installed:

# Install maturin
pip install maturin

# Build and install
maturin develop --release

Quick Start

from rsylla import Session

# Connect to ScyllaDB cluster
session = Session.connect(["127.0.0.1:9042"])

# Execute a query
result = session.execute(
    "SELECT * FROM system.local WHERE key = ?",
    {"key": "local"}
)

# Iterate over rows
for row in result:
    print(row.columns())

Usage Examples

Creating a Session

from rsylla import SessionBuilder

# Using SessionBuilder for advanced configuration
session = (
    SessionBuilder()
    .known_nodes(["127.0.0.1:9042", "127.0.0.2:9042"])
    .user("username", "password")
    .use_keyspace("my_keyspace", case_sensitive=False)
    .connection_timeout(5000)  # 5 seconds
    .pool_size(10)
    .compression("lz4")
    .tcp_nodelay(True)
    .build()
)

Executing Queries

# Simple query
result = session.execute("SELECT * FROM users")

# Query with parameters
result = session.execute(
    "SELECT * FROM users WHERE id = ?",
    {"id": 123}
)

# Get first row
row = result.first_row()
if row:
    print(row.columns())

# Get single row (raises exception if not exactly one row)
row = result.single_row()

# Iterate over all rows
for row in result:
    print(row[0], row[1], row[2])

Using Query Objects

from rsylla import Query

# Create a query with configuration
query = (
    Query("SELECT * FROM users WHERE id = ?")
    .with_consistency("QUORUM")
    .with_page_size(1000)
    .with_timeout(10000)
    .with_tracing(True)
)

result = session.query(query, {"id": 123})

# Check tracing info
if result.tracing_id():
    print(f"Trace ID: {result.tracing_id()}")

Prepared Statements

# Prepare a statement
prepared = session.prepare("INSERT INTO users (id, name, email) VALUES (?, ?, ?)")

# Execute prepared statement
result = session.execute_prepared(
    prepared,
    {"id": 1, "name": "John Doe", "email": "john@example.com"}
)

# Prepared statements with configuration
prepared = (
    prepared
    .with_consistency("LOCAL_QUORUM")
    .with_serial_consistency("SERIAL")
)

result = session.execute_prepared(prepared, {"id": 2, "name": "Jane", "email": "jane@example.com"})

Batch Operations

from rsylla import Batch

# Create a batch
batch = Batch("logged")  # or "unlogged" or "counter"

# Add statements to batch
batch.append_statement("INSERT INTO users (id, name) VALUES (?, ?)")
batch.append_statement("INSERT INTO users (id, name) VALUES (?, ?)")

# Configure batch
batch = (
    batch
    .with_consistency("QUORUM")
    .with_timestamp(1234567890)
)

# Execute batch with values for each statement
result = session.batch(
    batch,
    [
        {"id": 1, "name": "User 1"},
        {"id": 2, "name": "User 2"}
    ]
)

Working with Results

result = session.execute("SELECT * FROM users")

# Get all rows
rows = result.rows()
print(f"Found {len(rows)} rows")

# Get rows as dictionaries
rows_dict = result.rows_typed()
for row_dict in rows_dict:
    print(row_dict)

# Get column specifications
col_specs = result.col_specs()
for spec in col_specs:
    print(f"Column: {spec['name']}, Type: {spec['typ']}")

# Check for warnings
if result.warnings():
    print("Warnings:", result.warnings())

# Boolean check
if result:
    print("Query returned rows")

Keyspace Operations

# Change keyspace
session.use_keyspace("another_keyspace", case_sensitive=False)

# Get current keyspace
current_ks = session.get_keyspace()
print(f"Current keyspace: {current_ks}")

# Wait for schema agreement
agreed = session.await_schema_agreement()
print(f"Schema agreement reached: {agreed}")

Error Handling

from rsylla import ScyllaError

try:
    result = session.execute("INVALID QUERY")
except ScyllaError as e:
    print(f"Query error: {e}")

Consistency Levels

The following consistency levels are supported:

  • ANY
  • ONE
  • TWO
  • THREE
  • QUORUM
  • ALL
  • LOCAL_QUORUM (or LOCALQUORUM)
  • EACH_QUORUM (or EACHQUORUM)
  • LOCAL_ONE (or LOCALONE)

Serial consistency levels:

  • SERIAL
  • LOCAL_SERIAL (or LOCALSERIAL)

Batch Types

  • logged - Default, atomicity guaranteed
  • unlogged - No atomicity guarantee, better performance
  • counter - For counter updates

Compression Types

  • lz4 - LZ4 compression
  • snappy - Snappy compression
  • None - No compression

Type Mapping

Python types are automatically converted to CQL types:

Python Type CQL Type
bool boolean
int int, bigint
float float, double
str text, varchar
bytes blob
list list
dict map
None NULL

API Reference

SessionBuilder

  • known_node(hostname: str) - Add a known node
  • known_nodes(hostnames: List[str]) - Add multiple known nodes
  • use_keyspace(keyspace_name: str, case_sensitive: bool) - Set default keyspace
  • connection_timeout(duration_ms: int) - Set connection timeout
  • pool_size(size: int) - Set connection pool size
  • user(username: str, password: str) - Set authentication credentials
  • compression(compression: Optional[str]) - Set compression type
  • tcp_nodelay(nodelay: bool) - Enable/disable TCP_NODELAY
  • tcp_keepalive(keepalive_ms: Optional[int]) - Set TCP keepalive
  • build() - Build the session

Session

  • connect(nodes: List[str]) - Create a session (static method)
  • execute(query: str, values: Optional[Dict[str, Any]]) - Execute a query
  • query(query: Query, values: Optional[Dict[str, Any]]) - Execute a Query object
  • prepare(query: str) - Prepare a statement
  • execute_prepared(prepared: PreparedStatement, values: Optional[Dict[str, Any]]) - Execute prepared statement
  • batch(batch: Batch, values: List[Dict[str, Any]]) - Execute a batch
  • use_keyspace(keyspace_name: str, case_sensitive: bool) - Change keyspace
  • await_schema_agreement() - Wait for schema agreement
  • get_cluster_data() - Get cluster metadata
  • get_keyspace() - Get current keyspace

Query

  • __init__(query: str) - Create a query
  • with_consistency(consistency: str) - Set consistency level
  • with_serial_consistency(serial_consistency: str) - Set serial consistency
  • with_page_size(page_size: int) - Set page size
  • with_timestamp(timestamp: int) - Set timestamp
  • with_timeout(timeout_ms: int) - Set timeout
  • with_tracing(tracing: bool) - Enable/disable tracing
  • is_idempotent() - Check if idempotent
  • set_idempotent(idempotent: bool) - Set idempotency
  • get_contents() - Get query string

PreparedStatement

Similar methods to Query, plus:

  • get_id() - Get prepared statement ID
  • get_statement() - Get query string

QueryResult

  • rows() - Get all rows
  • first_row() - Get first row or None
  • single_row() - Get single row (raises exception if not exactly one)
  • first_row_typed() - Get first row as dictionary
  • rows_typed() - Get all rows as dictionaries
  • col_specs() - Get column specifications
  • tracing_id() - Get tracing ID
  • warnings() - Get query warnings
  • Supports iteration, len(), and boolean checks

Row

  • columns() - Get all column values
  • as_dict() - Convert to dictionary
  • get(index: int) - Get column by index
  • Supports indexing with [] and len()

Batch

  • __init__(batch_type: str) - Create a batch
  • append_statement(query: str) - Add a statement
  • append_query(query: Query) - Add a Query object
  • append_prepared(prepared: PreparedStatement) - Add a prepared statement
  • with_consistency(consistency: str) - Set consistency level
  • with_serial_consistency(serial_consistency: str) - Set serial consistency
  • with_timestamp(timestamp: int) - Set timestamp
  • with_timeout(timeout_ms: int) - Set timeout
  • with_tracing(tracing: bool) - Enable/disable tracing
  • is_idempotent() - Check if idempotent
  • set_idempotent(idempotent: bool) - Set idempotency
  • statements_count() - Get number of statements

License

This project is dual-licensed under MIT or Apache-2.0, matching the scylla-rust-driver license.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

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

rsylla-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl (2.3 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.34+ x86-64

File details

Details for the file rsylla-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for rsylla-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 3a299c11dc4c876f72aea94753986f7eed733f30b7b1c3d666207e21c636ada1
MD5 9bafa970cb03500ac3d3e40af4f9f934
BLAKE2b-256 4e9ccbdd59c8cbce4d5048a96576cb8d823d12700784ee47ed1677eff4d9e52d

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