Skip to main content

Universal, framework-independent ORM for Python.

Project description

Akron ORM Logo

Akron

Universal, framework-independent ORM for Python 🚀

Akron is a modern Python ORM that provides a unified interface for working with multiple databases. Whether you're using SQLite, MySQL, PostgreSQL, or MongoDB, Akron gives you the same clean, type-safe API across all platforms.

PyPI version Python 3.7+ License: MIT


✨ Key Features

  • 🔄 Universal Database Support - One API for SQLite, MySQL, PostgreSQL, and MongoDB
  • 🛡️ Type Safety - Full Pydantic integration for type-safe models and validation
  • 🔧 Zero Configuration - Works out of the box with simple connection strings
  • 🔗 Foreign Key Support - Multi-table relationships with automatic constraint handling
  • 📦 Auto Migrations - Schema tracking and automatic migration generation
  • ⚡ CLI Tools - Command-line interface for database management
  • 🧪 Well Tested - Comprehensive test coverage across all database drivers
  • 📖 Framework Independent - Works with any Python framework or standalone scripts

🚀 Quick Start

Installation

pip install akron

Basic Usage

from akron import Akron

# Initialize database connection
db = Akron("sqlite:///example.db")

# Create table
db.create_table("users", {
    "id": "int",
    "name": "str", 
    "email": "str",
    "age": "int"
})

# Insert data
user_id = db.insert("users", {
    "name": "Alice Johnson",
    "email": "alice@example.com", 
    "age": 28
})

# Query data
users = db.find("users")
alice = db.find("users", {"name": "Alice Johnson"})

# Update records
db.update("users", {"id": user_id}, {"age": 29})

# Delete records
db.delete("users", {"email": "alice@example.com"})

# Close connection
db.close()

Type-Safe Models with Pydantic

from pydantic import BaseModel
from akron import Akron
from akron.models import ModelMixin

class User(BaseModel, ModelMixin):
    id: int
    name: str
    email: str
    age: int
    is_active: bool = True

# Initialize database
db = Akron("sqlite:///users.db")

# Create table from model
User.create_table(db)

# Insert with type safety
new_user = User(id=1, name="Bob Smith", email="bob@example.com", age=25)
User.insert(db, new_user)

# Query with automatic deserialization
users = User.find(db)  # Returns List[User]
active_users = User.find(db, {"is_active": True})

# Update and delete
User.update(db, {"id": 1}, {"age": 26})
User.delete(db, {"email": "bob@example.com"})

🗄️ Database Support

Database Connection String Example CRUD Foreign Keys Migrations CLI Support
SQLite sqlite:///path/to/db.db
MySQL mysql://user:pass@host:port/dbname
PostgreSQL postgres://user:pass@host:port/dbname
MongoDB mongodb://host:port/dbname ❌* Schemaless

*MongoDB doesn't support traditional foreign keys but maintains the same API for document references.

Connection Examples

# SQLite (file-based)
db = Akron("sqlite:///myapp.db")

# SQLite (in-memory)
db = Akron("sqlite:///:memory:")

# MySQL
db = Akron("mysql://username:password@localhost:3306/mydatabase")

# PostgreSQL
db = Akron("postgres://username:password@localhost:5432/mydatabase")

# MongoDB
db = Akron("mongodb://localhost:27017/mydatabase")

🔗 Advanced Features

Foreign Key Relationships

# Create tables with foreign key relationships
db.create_table("users", {
    "id": "int",
    "name": "str",
    "email": "str"
})

db.create_table("orders", {
    "id": "int",
    "user_id": "int->users.id",  # Foreign key syntax
    "product_name": "str",
    "amount": "float",
    "status": "str"
})

# Insert related data
user_id = db.insert("users", {"name": "Alice", "email": "alice@example.com"})
order_id = db.insert("orders", {
    "user_id": user_id,
    "product_name": "Laptop",
    "amount": 999.99,
    "status": "pending"
})

# Query with relationships
user_orders = db.find("orders", {"user_id": user_id})

Complex Queries and Filtering

# Multiple filter conditions
adults = db.find("users", {"age": 25, "is_active": True})

# Range queries (depends on driver capabilities)
expensive_orders = db.find("orders", {"amount": ">500"})

# Get all records
all_users = db.find("users")  # No filters = all records

Pydantic Model Relationships

class User(BaseModel, ModelMixin):
    id: int
    name: str
    email: str
    age: int

class Order(BaseModel, ModelMixin):
    id: int
    user_id: int  # Foreign key reference
    product_name: str
    amount: float
    status: str

# Create tables
User.create_table(db)
Order.create_table(db)

# Work with related models
user = User(id=1, name="Charlie", email="charlie@example.com", age=30)
User.insert(db, user)

order = Order(id=1, user_id=1, product_name="Book", amount=24.99, status="shipped")
Order.insert(db, order)

# Query relationships
user_orders = Order.find(db, {"user_id": 1})

🔄 Schema Management (Prisma-like)

Akron now supports Prisma-like schema management with akron.json configuration files:

Initialize a New Project

# Initialize with SQLite (default)
akron db init

# Initialize with specific database
akron db init --provider postgresql --url "postgres://user:pass@localhost:5432/mydb"
akron db init --provider mysql --url "mysql://user:pass@localhost:3306/mydb"
akron db init --provider mongodb --url "mongodb://localhost:27017/mydb"

Define Your Schema

Edit the generated akron.json file:

{
  "database": {
    "provider": "sqlite",
    "url": "sqlite:///app.db"
  },
  "tables": {
    "users": {
      "columns": {
        "id": {
          "type": "int",
          "primary_key": true,
          "auto_increment": true
        },
        "email": {
          "type": "str",
          "unique": true,
          "nullable": false
        },
        "username": {
          "type": "str",
          "unique": true,
          "nullable": false,
          "max_length": 50
        },
        "created_at": {
          "type": "datetime",
          "default": "CURRENT_TIMESTAMP"
        }
      }
    },
    "posts": {
      "columns": {
        "id": {
          "type": "int",
          "primary_key": true,
          "auto_increment": true
        },
        "title": {
          "type": "str",
          "nullable": false,
          "max_length": 200
        },
        "content": {
          "type": "text",
          "nullable": true
        },
        "author_id": {
          "type": "int",
          "nullable": false
        },
        "published": {
          "type": "bool",
          "default": false
        }
      },
      "foreign_keys": {
        "author_id": {
          "references": "users",
          "column": "id",
          "on_delete": "CASCADE"
        }
      }
    }
  }
}

Generate and Apply Migrations

# Generate migrations from schema changes
akron db makemigrations --name "add_user_posts"

# Preview what will be migrated
akron db migrate --dry-run

# Apply migrations
akron db migrate

# Check migration status
akron db status

Schema Management Workflow

  1. Initialize: akron db init creates akron.json and .akron/ directory
  2. Define: Edit akron.json to define your database schema
  3. Generate: akron db makemigrations creates migration files
  4. Apply: akron db migrate applies pending migrations
  5. Monitor: akron db status shows current state

🔄 Legacy Migration System

For backward compatibility, Akron still supports the original migration commands:

Auto-Generate Migrations

# Create a migration for schema changes
akron makemigrations users --db sqlite:///app.db --schema '{"id": "int", "name": "str", "email": "str", "created_at": "str"}'

# Apply migrations
akron migrate users --db sqlite:///app.db

# View migration history
akron showmigrations users --db sqlite:///app.db

Migration Features

  • Automatic Schema Diffing - Compares current vs target schema
  • Migration File Generation - Creates JSON migration files in migrations/ directory
  • Version Tracking - Maintains migration history in _akron_migrations table
  • Rollback Support - Track applied migrations for potential rollbacks

🛠️ CLI Commands

Akron provides two command interfaces: modern schema management and legacy commands.

Modern Schema Management Commands

# Initialize a new Akron project
akron db init                                      # SQLite default
akron db init --provider postgresql --url "..."   # PostgreSQL
akron db init --provider mysql --url "..."        # MySQL
akron db init --provider mongodb --url "..."      # MongoDB

# Generate migrations from schema changes
akron db makemigrations                            # Auto-named migration
akron db makemigrations --name "add_user_table"   # Custom name

# Apply migrations
akron db migrate                                   # Apply all pending
akron db migrate --dry-run                        # Preview changes

# Check status
akron db status                                    # Show schema and migration status

# Reset database (planned)
akron db reset --force                            # Drop all and reapply

Legacy Commands (Backward Compatibility)

# Table Management
akron create-table users --db sqlite:///app.db --schema '{"id": "int", "name": "str"}'
akron drop-table users --db sqlite:///app.db
akron inspect-schema users --db sqlite:///app.db

# Data Management
akron seed users --db sqlite:///app.db --data '{"name": "John", "email": "john@example.com"}'
akron raw-sql --db sqlite:///app.db --sql "SELECT COUNT(*) FROM users"

# Legacy Migration Commands
akron makemigrations orders --db mysql://user:pass@localhost/shop --schema '{"id": "int"}'
akron migrate orders --db mysql://user:pass@localhost/shop
akron showmigrations orders --db mysql://user:pass@localhost/shop

📊 Type System

Akron provides a flexible type system that maps Python types to database-specific types:

Supported Python Types

Python Type SQL Databases MongoDB
int INTEGER Number
str VARCHAR/TEXT String
float REAL/DOUBLE Number
bool BOOLEAN Boolean

Custom Type Mapping

# Define custom field types in Pydantic models
from pydantic import Field
from datetime import datetime

class User(BaseModel, ModelMixin):
    id: int
    name: str
    email: str = Field(..., max_length=255)
    age: int = Field(..., ge=0, le=150)
    created_at: str  # Store as ISO string
    is_premium: bool = False

🔧 Configuration & Best Practices

Connection Pooling

# For production use, consider connection pooling
class DatabaseManager:
    def __init__(self, db_url: str):
        self.db_url = db_url
        self._db = None
    
    def get_db(self):
        if self._db is None:
            self._db = Akron(self.db_url)
        return self._db
    
    def close(self):
        if self._db:
            self._db.close()
            self._db = None

# Usage
db_manager = DatabaseManager("sqlite:///app.db")
db = db_manager.get_db()

Error Handling

from akron.exceptions import AkronError, TableNotFoundError, SchemaError

try:
    db = Akron("sqlite:///myapp.db")
    users = db.find("nonexistent_table")
except TableNotFoundError:
    print("Table doesn't exist - creating it...")
    db.create_table("users", {"id": "int", "name": "str"})
except AkronError as e:
    print(f"Database error: {e}")

Environment-Based Configuration

import os
from akron import Akron

# Use environment variables for database configuration
DATABASE_URL = os.getenv(
    "DATABASE_URL", 
    "sqlite:///default.db"  # fallback for development
)

db = Akron(DATABASE_URL)

🧪 Testing

Akron includes comprehensive test coverage and provides utilities for testing:

Test Database Setup

import pytest
from akron import Akron
from akron.models import ModelMixin
from pydantic import BaseModel

class User(BaseModel, ModelMixin):
    id: int
    name: str
    email: str

@pytest.fixture
def test_db():
    # Use in-memory database for testing
    db = Akron("sqlite:///:memory:")
    User.create_table(db)
    yield db
    db.close()

def test_user_creation(test_db):
    user = User(id=1, name="Test User", email="test@example.com")
    User.insert(test_db, user)
    
    users = User.find(test_db, {"email": "test@example.com"})
    assert len(users) == 1
    assert users[0].name == "Test User"

Running Tests

# Run the full test suite
pytest tests/

# Run specific database tests
pytest tests/test_sqlite_pytest.py
pytest tests/test_mysql_pytest.py

📈 Performance Considerations

Batch Operations

# For large datasets, consider batch insertions
users_data = [
    {"name": f"User {i}", "email": f"user{i}@example.com", "age": 20 + i}
    for i in range(1000)
]

for user_data in users_data:
    db.insert("users", user_data)

Connection Management

# Always close connections in production
try:
    db = Akron("mysql://user:pass@localhost/prod_db")
    # ... database operations ...
finally:
    db.close()

# Or use context managers (if implementing __enter__/__exit__)

🔍 Examples

Check out the examples/ directory for more comprehensive examples:

  • basic_crud.py - Basic CRUD operations
  • sqlite_multi_table.py - Multi-table relationships with SQLite
  • postgres_multi_table.py - PostgreSQL with foreign keys

🆚 Version Information

  • Current Version: v0.1.5
  • Python Requirements: Python 3.7+
  • Dependencies:
    • pydantic - Type safety and validation
    • mysql-connector-python - MySQL support
    • psycopg2 - PostgreSQL support
    • pymongo - MongoDB support

Changelog

See CHANGELOG.md for detailed version history and updates.


🤝 Contributing

We welcome contributions! Please feel free to:

  1. Report Issues - Found a bug? Let us know!
  2. Feature Requests - Have an idea? We'd love to hear it!
  3. Pull Requests - Code contributions are always welcome!

Development Setup

# Clone the repository
git clone https://github.com/Akash-nath29/akron.git
cd akron

# Install development dependencies
pip install -e .
pip install pytest

# Run tests
pytest tests/

📄 License

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


🔗 Links


Made with ❤️ by the Akron team

Star us on GitHub if you find Akron useful!

Project details


Download files

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

Source Distribution

akron-0.2.0.tar.gz (28.0 kB view details)

Uploaded Source

Built Distribution

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

akron-0.2.0-py3-none-any.whl (25.9 kB view details)

Uploaded Python 3

File details

Details for the file akron-0.2.0.tar.gz.

File metadata

  • Download URL: akron-0.2.0.tar.gz
  • Upload date:
  • Size: 28.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.5

File hashes

Hashes for akron-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f96b66a982b3bc94c6777412bb22032284a53c168cc444fcaf79368276724512
MD5 6d34e7f83b5090f99813257919011556
BLAKE2b-256 54f234e87ce7c70da80a58c251406bc364a7f5e8315002b5d2151dc52b52a896

See more details on using hashes here.

File details

Details for the file akron-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: akron-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 25.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.5

File hashes

Hashes for akron-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6abb96680083273c41c8d296458cf8024ab1a8f4bc4e316059889641061f97e0
MD5 54bf52e15c17401e50da588a9ab0425f
BLAKE2b-256 a5c4487fb6ce32ecb50bd0be1713734987c328efdc0b2c6aedb0533f704af3c3

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