Skip to main content

Python testing library for PGlite - in-memory PostgreSQL for tests

Project description

py-pglite

py-pglite Logo

A Pythonic interface for PGlite - the instant, zero-config PostgreSQL. ⚡️

py-pglite brings the magic of PGlite to Python with a high-level, developer-friendly API. Real PostgreSQL, instant testing.

pip install py-pglite


def test_users(pglite_session):
    user = User(name="Alice")
    pglite_session.add(user)
    pglite_session.commit()
    assert user.id == 1  # It's real PostgreSQL!

That's it. No Docker, no setup, no config files. Real PostgreSQL, instant testing.

CI PyPI Python

License MyPy Ruff codecov


Why py-pglite?

# ❌ Traditional testing
def test_old_way():
    # 1. Install PostgreSQL
    # 2. Configure connection  
    # 3. Manage test databases
    # 4. Handle cleanup
    # 5. Docker containers...
    pass

# ✅ py-pglite way  
def test_new_way(pglite_session):
    User.objects.create(name="Alice")  # Just works!

The magic:

  • 🎯 Zero config - No setup, no Docker, no servers
  • Instant - 2-3s startup vs 30-60s Docker
  • 🔄 Isolated - Fresh database per test
  • 🐘 Real PostgreSQL - JSON, arrays, window functions
  • 🚀 Any client - SQLAlchemy, Django, psycopg, asyncpg

Install

# Core (framework-agnostic)
pip install py-pglite

# With your stack
pip install py-pglite[sqlalchemy]  # SQLAlchemy + SQLModel
pip install py-pglite[django]      # Django + pytest-django  
pip install py-pglite[asyncpg]     # Pure async client
pip install py-pglite[all]         # Everything

# Extra Features
pip install py-pglite[extensions]  # pglite extensions, like pgvector, fuzzystrmatch etc.

Quick Start

SQLAlchemy (Zero imports needed)

def test_sqlalchemy_just_works(pglite_session):
    user = User(name="Alice", email="alice@test.com")  
    pglite_session.add(user)
    pglite_session.commit()
    
    assert user.id is not None
    assert User.query.count() == 1  # Real PostgreSQL!

Django

🔹 Lightweight/Socket (Minimal setup)

def test_django_socket_pattern(configured_django):
    Post.objects.create(title="Hello", content="World")
    assert Post.objects.count() == 1  # Real PostgreSQL via socket!

🔸 Full Integration/Backend (Enhanced features)

def test_django_backend_pattern(django_pglite_db):
    Post.objects.create(title="Hello", content="World", metadata={"tags": ["test"]})
    assert Post.objects.count() == 1  # Custom backend with JSON support!

Choose your pattern:

  • Lightweight: Fast, minimal dependencies, standard PostgreSQL backend
  • Full Integration: Advanced features, custom backend, enhanced JSON support

👉 See Django patterns guide for detailed examples and migration guide.

Any PostgreSQL client

def test_any_client_works(pglite_manager):
    # Extract connection details
    engine = pglite_manager.get_engine()
    host, port, database = str(engine.url.host), engine.url.port, engine.url.database
    
    # Use with any PostgreSQL client
    # conn = psycopg.connect(host=host, port=port, dbname=database)
    # conn = await asyncpg.connect(host=host, port=port, database=database)
    # engine = create_async_engine(f"postgresql+asyncpg://{host}:{port}/{database}")

Examples

FastAPI + SQLModel

from fastapi.testclient import TestClient

def test_api_endpoint(client: TestClient):
    response = client.post("/users/", json={"name": "Alice"})
    assert response.status_code == 201
    
    response = client.get("/users/")
    assert len(response.json()) == 1

PostgreSQL Features

def test_postgresql_power(pglite_session):
    pglite_session.execute(text("""
        CREATE TABLE analytics (
            data JSONB,
            tags TEXT[],
            created TIMESTAMP DEFAULT NOW()
        )
    """))
    
    pglite_session.execute(text("""
        INSERT INTO analytics (data, tags) VALUES 
        ('{"clicks": 100}', ARRAY['web', 'mobile'])
    """))
    
    result = pglite_session.execute(text("""
        SELECT data->>'clicks' as clicks,
               array_length(tags, 1) as tag_count
        FROM analytics 
        WHERE data->>'clicks' > '50'
    """)).fetchone()
    
    assert result.clicks == '100'

PostgreSQL Extensions

py-pglite supports PostgreSQL extensions, allowing you to test advanced features like vector similarity search for AI/RAG applications.

🚀 pgvector for RAG Applications

Enable pgvector to test vector embeddings and similarity search directly in your test suite.

1. Install with the [extensions] extra:

pip install 'py-pglite[extensions]'

2. Enable pgvector in the configuration:

from py_pglite import PGliteConfig, PGliteManager
from pgvector.psycopg import register_vector
import psycopg
import numpy as np

# Enable the extension
config = PGliteConfig(extensions=["pgvector"])

with PGliteManager(config=config) as db:
    with psycopg.connect(db.get_dsn(), autocommit=True) as conn:
        # Create the extension and register the type
        conn.execute("CREATE EXTENSION IF NOT EXISTS vector")
        register_vector(conn)

        # Create a table and insert a vector
        conn.execute("CREATE TABLE items (embedding vector(3))")
        conn.execute("INSERT INTO items (embedding) VALUES (%s)", (np.array([1, 2, 3]),))
        
        # Perform a similarity search
        result = conn.execute("SELECT * FROM items ORDER BY embedding <-> %s LIMIT 1", (np.array([1, 1, 1]),)).fetchone()
        assert np.array_equal(result[0], np.array([1, 2, 3]))

py-pglite can support many other extensions available in the underlying PGlite extensions ♥️.


Advanced

🔧 Production Configuration
from py_pglite import PGliteConfig
from py_pglite.sqlalchemy import SQLAlchemyPGliteManager

config = PGliteConfig(
    timeout=60,                    # Extended timeout for CI/CD
    log_level="INFO",              # Balanced logging
    cleanup_on_exit=True,          # Automatic cleanup
    work_dir=Path("./test-data")   # Custom directory
)

with SQLAlchemyPGliteManager(config) as manager:
    engine = manager.get_engine(
        pool_recycle=3600,         # Connection recycling
        echo=False                 # SQL logging
    )
🔄 Client Compatibility
# py-pglite provides a REAL PostgreSQL server - any client works!

with SQLAlchemyPGliteManager() as manager:
    engine = manager.get_engine()
    url = engine.url
    
    # Extract connection details for any PostgreSQL client
    host, port, database = str(url.host), url.port, url.database
    
    # Examples for different clients:
    # psycopg:  psycopg.connect(host=host, port=port, dbname=database)
    # asyncpg:  await asyncpg.connect(host=host, port=port, database=database)
    # Django:   Uses custom py-pglite backend automatically

Installation Matrix:

Client Install Use Case
[sqlalchemy] SQLAlchemy + SQLModel ORM, modern Python
[django] Django + pytest-django Django projects
[psycopg] psycopg (sync/async) Raw SQL, custom
[asyncpg] Pure async client High-performance async
[all] Everything Full compatibility
🎯 Framework Isolation
# Perfect isolation - no framework bleeding
pytest -m sqlalchemy -p no:django     # Pure SQLAlchemy
pytest -m django -p no:sqlalchemy     # Pure Django  
pytest tests/sqlalchemy/              # Directory isolation

Built for developers who want PostgreSQL testing without the complexity.

🎯 Examples • 📚 Contributing • 🐛 Issues


py-pglite: Because testing should be simple.

Powered by the 🚀 amazing and ♥️ beloved PGlite.

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

py_pglite-0.4.1.tar.gz (273.4 kB view details)

Uploaded Source

Built Distribution

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

py_pglite-0.4.1-py3-none-any.whl (40.5 kB view details)

Uploaded Python 3

File details

Details for the file py_pglite-0.4.1.tar.gz.

File metadata

  • Download URL: py_pglite-0.4.1.tar.gz
  • Upload date:
  • Size: 273.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for py_pglite-0.4.1.tar.gz
Algorithm Hash digest
SHA256 853a3b7b9a78660c08d6290a99a967d9d04cd001a43aeb4ba6e013cd3d29e3d1
MD5 f0e37b791cefa91ecad01326a011af3a
BLAKE2b-256 84755e6adeb27bdfc792275ac94c567eb9b73eac7e018666c23be88a9eb3e9b2

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_pglite-0.4.1.tar.gz:

Publisher: release.yml on wey-gu/py-pglite

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file py_pglite-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: py_pglite-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 40.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for py_pglite-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2741a5e02002d6e3e6b786d1d6f064ebe161a3d6d0cab4722f7d89a8b047dad6
MD5 8d3be74f6f9c107e57556e10bf8659d4
BLAKE2b-256 08704bc28d4067bb85fe2e70cf40f5be68af1fcfd7f3a06d6452ff62b3371e36

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_pglite-0.4.1-py3-none-any.whl:

Publisher: release.yml on wey-gu/py-pglite

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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