Skip to main content

Welcome to Coraline

Python Version PyPI Version License Build Status

Coraline is a Python library that provides a seamless integration between Pydantic models and AWS DynamoDB tables. It allows you to define your data models using Pydantic's powerful validation system and easily map them to DynamoDB tables.

Features

  • Define DynamoDB tables using Pydantic models
  • Automatic table creation and management
  • Type validation and conversion
  • Support for complex data types
  • Easy configuration of AWS credentials
  • Simplified CRUD operations

Installation

# Basic installation
pip install coraline

# With boto3 dependency
pip install coraline[boto]

Documentation

Architecture

graph TD
    A[Pydantic Model] -->|Extends| B[CoralModel]
    B -->|Creates/Manages| C[DynamoDB Table]
    B -->|Validates| D[Data]
    D -->|Stored in| C
    E[AWS Credentials] -->|Configure| B
    F[CoralConfig] -->|Configure| B

Quick Start

Define Your Model

import uuid
from enum import Enum
from coraline import CoralModel, KeyField, HashType
from pydantic import SecretStr, Field


class UserType(Enum):
    USER = "USER"
    ADMIN = "ADMIN"


class Users(CoralModel):
    user_id: uuid.UUID = KeyField(
        default=lambda: uuid.uuid4(),
        hash_key=HashType.HASH,
        alias="userId"
    )
    user_type: UserType = KeyField(
        ...,
        hash_type=HashType.RANGE,
        alias="userType"
    )
    name: str
    age: int = Field(..., gt=0)
    password: SecretStr


# Create the table if it doesn't exist
Users.get_or_create_table()

# Create and save a new user
new_user = Users(
    name="John Doe",
    user_type=UserType.USER,
    age=30,
    password="123456"
)
new_user.save()

This example:

  1. Defines a Users model that extends CoralModel
  2. Creates a DynamoDB table named Users with:
    • PAY_PER_REQUEST billing mode (default)
    • userId (String) as the Hash Key
    • userType (String) as the Range Key
    • Additional fields: name (String), age (Number), and password (String)
  3. Creates and saves a new user record to the table

Table Configuration

Use the CoralConfig class to customize your DynamoDB table settings.

import uuid
from enum import Enum
from coraline import (
    CoralModel,
    KeyField,
    HashType,
    CoralConfig,
    BillingMode,
    TableClass
)
from pydantic import SecretStr, Field


class UserType(Enum):
    USER = "USER"
    ADMIN = "ADMIN"


def to_camel(string: str) -> str:
    """Convert snake_case to camelCase"""
    return ''.join(word.capitalize() for word in string.split('_'))


# CoralModel is a subclass of Pydantic's BaseModel
class Users(CoralModel):
    # CoralConfig is a subclass of Pydantic's ConfigDict
    model_config = CoralConfig(
        # Custom table name (default is the class name)
        table_name="MyUsers",

        # Set billing mode to PROVISIONED (default is PAY_PER_REQUEST)
        billing_mode=BillingMode.PROVISIONED,
        read_capacity_units=5,
        write_capacity_units=5,

        # Convert field names to camelCase in DynamoDB
        alias_generator=to_camel,

        # Prevent fields from being excluded when None
        protect_from_exclusion=True,

        # Set table storage class
        table_class=TableClass.STANDARD_INFREQUENT_ACCESS,

        # Add any additional parameters accepted by boto3's create_table
        extra_table_params={
            "Tags": [
                {
                    "Key": "Project",
                    "Value": "MyProject"
                }
            ]
        }
    )

    # KeyField is a subclass of Pydantic's Field
    user_id: uuid.UUID = KeyField(
        default=lambda: uuid.uuid4(),
        hash_key=HashType.HASH
    )
    user_type: UserType = KeyField(
        ...,
        hash_type=HashType.RANGE
    )
    name: str
    age: int = Field(..., gt=0)
    password: SecretStr

Available Configuration Options

Option Description Default
table_name Custom name for the DynamoDB table Class name
billing_mode BillingMode.PROVISIONED or BillingMode.PAY_PER_REQUEST BillingMode.PAY_PER_REQUEST
read_capacity_units Read capacity units (when using PROVISIONED) 5
write_capacity_units Write capacity units (when using PROVISIONED) 5
alias_generator Function to transform field names None
protect_from_exclusion Prevent fields from being excluded when None False
table_class Storage class for the table TableClass.STANDARD
extra_table_params Additional parameters for boto3's create_table {}

AWS Credentials Configuration

Coraline provides multiple ways to configure AWS credentials for connecting to DynamoDB. The library follows a priority order when determining which credentials to use:

  1. Class-specific configuration in model_config
  2. Coraline environment variables
  3. Standard AWS environment variables

Environment Variables

You can set AWS credentials using environment variables:

# Standard AWS environment variables
AWS_REGION="us-east-1"
AWS_ACCESS_KEY_ID="your-access-key"
AWS_SECRET_ACCESS_KEY="your-secret-key"

# Coraline-specific environment variables (take precedence)
CORALINE_AWS_REGION="us-west-2"
CORALINE_AWS_ACCESS_KEY_ID="your-coraline-access-key"
CORALINE_AWS_SECRET_ACCESS_KEY="your-coraline-secret-key"
CORALINE_AWS_ENDPOINT_URL="http://localhost:8000"  # For local development

Model Configuration

You can specify AWS credentials directly in your model configuration:

from coraline import CoralModel, CoralConfig

class Users(CoralModel):
    model_config = CoralConfig(
        # AWS credentials
        aws_region="us-east-1",
        aws_access_key_id="your-access-key",
        aws_secret_access_key="your-secret-key",
        aws_endpoint_url="http://localhost:8000"  # For local development
    )

Using Boto3 Config

For more advanced configuration, you can use a boto3 Config instance:

from botocore.config import Config
from coraline import CoralModel, CoralConfig

# Create a boto3 Config instance
config = Config(
    region_name="us-east-1",
    endpoint_url="http://localhost:8000",
    retries={
        'max_attempts': 10,
        'mode': 'standard'
    }
)

class Users(CoralModel):
    model_config = CoralConfig(
        aws_config=config
    )

Local Development

For local development with DynamoDB Local:

from coraline import CoralModel, CoralConfig

class Users(CoralModel):
    model_config = CoralConfig(
        aws_region="local",
        aws_endpoint_url="http://localhost:8000"
    )

Basic Operations

Coraline provides a set of methods to interact with DynamoDB tables. Here are the most common operations:

Table Operations

Create or Get Table

Creates a new table if it doesn't exist, or returns information about the existing table:

# Create the table if it doesn't exist
table_description: dict = Users.get_or_create_table()

# Get the table name (returns "Users" by default, or the custom name if specified)
table_name: str = Users.get_table_name()

Get Table Information

Retrieve detailed information about the table:

# Get basic table information
table_info: dict = Users.get_table_info()

# Include additional describe operations
table_info: dict = Users.get_table_info(
    include=[
        "describe_continuous_backups",
        "describe_time_to_live"
    ]
)

Note: Only describe operations that take just the TableName parameter are supported, such as:

  • describe_continuous_backups
  • describe_time_to_live
  • describe_limits

Operations that require additional parameters (like describe_backup, describe_global_table) are not supported through this method.

Record Operations

Check if a Record Exists

Check if a record exists by providing all hash and range keys:

# Check if a user exists
user_exists: bool = Users.exists(
    user_id="12345678-1234-1234-1234-123456789012",
    user_type=UserType.USER
)

Get a Record

Retrieve a record by providing all hash and range keys:

# Get a user
user: Users = Users.get(
    user_id="12345678-1234-1234-1234-123456789012",
    user_type=UserType.USER
)

# Access user properties
print(f"User name: {user.name}")
print(f"User age: {user.age}")

Create and Save a Record

Create a new record and save it to the table:

# Create a new user
new_user = Users(
    name="John Doe",
    user_type=UserType.USER,
    age=30,
    password="123456"
)

# Save the user to the table
new_user.save()

Update a Record

Update an existing record:

# Get an existing user
user = Users.get(
    user_id="12345678-1234-1234-1234-123456789012",
    user_type=UserType.USER
)

# Update properties
user.name = "Jane Doe"
user.age = 31

# Save the changes
user.save()

Delete a Record

Delete an existing record:

# Get an existing user
user = Users.get(
    user_id="12345678-1234-1234-1234-123456789012",
    user_type=UserType.USER
)

# Delete the user
user.delete()

# You can also use the async version
await user.adelete()

# Verify the user no longer exists
user_exists = Users.exists(
    user_id="12345678-1234-1234-1234-123456789012",
    user_type=UserType.USER
)
assert user_exists is False

Advanced Operations

Using boto3's Client Directly

For operations not covered by Coraline's methods, you can access the boto3 client directly:

# Get the boto3 client
client = Users.get_client()

# Use any boto3 DynamoDB client method
client.create_backup(
    TableName=Users.get_table_name(),
    BackupName="MyBackup"
)

# Or from an instance
user = Users.get(
    user_id="12345678-1234-1234-1234-123456789012",
    user_type=UserType.USER
)
user.get_client().update_time_to_live(
    TableName=user.table_name(),
    TimeToLiveSpecification={
        'Enabled': True,
        'AttributeName': 'ExpirationTime'
    }
)

Contributing

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

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'feat: add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please make sure to update tests as appropriate.

Issues and Support

If something isn't working as expected, don't panic. Get a towel and please open an issue.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Metadata

Release files for coraline 1.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for coraline 1.4.1
File Size Uploaded Provenance
coraline-1.4.1.tar.gz 13.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for coraline 1.4.1
File Interpreter ABI Platform
coraline-1.4.1-py3-none-any.whl Python 3 none any Details

Total release size: 26.6 kB

Release files / coraline-1.4.1.tar.gz

Download URL coraline-1.4.1.tar.gz
Size 13.9 kB
Tags Source
SHA-256 checksum
How to use checksums
a4a987fc83bd397540c56fb6a003e748c677d0cbde8d9a3a1c10b6d4b537c738
BLAKE2b-256 checksum
How to use checksums
ad3baba9f37be5cf19e8c0f58b9b925d59d13e31be64de97831ff590a1a23007
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.1 CPython/3.12.1 Linux/6.11.0-1018-azure

Release files / coraline-1.4.1-py3-none-any.whl

Download URL coraline-1.4.1-py3-none-any.whl
Size 12.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f17aff581a9ad7931d2f4bc85cdfafedd6b2af7fa8f75b4db3a0048c51cdf6e5
BLAKE2b-256 checksum
How to use checksums
b610e99c0d36be2b27a77dbb805a3a56b40a426f56c6a1b7c79cc56023bed946
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.1 CPython/3.12.1 Linux/6.11.0-1018-azure

Security for coraline 1.4.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page