Skip to main content

A PostgreSQL database framework for Python using psycopg3 with connection pooling, thread-safety, and repository pattern

Project description

PyPGKit

PyPI version Python versions License Tests codecov Code style: ruff

A PostgreSQL database framework for Python using psycopg3 with connection pooling, thread-safety, and repository pattern.

Features

  • Connection Pooling: Thread-safe connection pool using psycopg_pool
  • Singleton Pattern: Global database instance with Database.init() and Database.get_instance()
  • Repository Pattern: Base repository class with CRUD operations
  • Automatic Setup: Create database, user, and schema automatically
  • Fork Safety: Compatible with gunicorn and other forking servers
  • Configurable Logging: Built-in logging with multiple formats
  • Type Hints: Full type annotations for better IDE support

Installation

pip install PyPGKit

Quick Start

Basic Usage

from pypgkit import Database, DatabaseConfig

# Initialize once at application startup
config = DatabaseConfig(
    host="localhost",
    port=5432,
    database="myapp",
    user="myuser",
    password="mypassword",
)

# This creates the database/user if needed and initializes the connection pool
Database.init(config=config, schema_path="schemas/init.sql")

# Use anywhere in your application
db = Database.get_instance()

# Execute queries
users = db.fetch_all("SELECT * FROM users WHERE active = %s", (True,))

Environment Variables

pypgkit supports configuration via environment variables:

export PYPGKIT_HOST=localhost
export PYPGKIT_PORT=5432
export PYPGKIT_DATABASE=myapp
export PYPGKIT_USER=myuser
export PYPGKIT_PASSWORD=mypassword
from pypgkit import Database, DatabaseConfig

# Load from environment
config = DatabaseConfig.from_env()
Database.init(config=config)

Repository Pattern

Create type-safe repositories for your entities:

from dataclasses import dataclass
from typing import Optional
from pypgkit import Database
from pypgkit.repositories import BaseRepository

@dataclass
class User:
    id: Optional[int] = None
    email: str = ""
    name: str = ""
    active: bool = True

class UserRepository(BaseRepository[User]):
    table_name = "users"
    primary_key = "id"

    def _row_to_entity(self, row: dict) -> User:
        return User(
            id=row.get("id"),
            email=row.get("email", ""),
            name=row.get("name", ""),
            active=row.get("active", True),
        )

    def _entity_to_row(self, entity: User) -> dict:
        row = {"email": entity.email, "name": entity.name, "active": entity.active}
        if entity.id is not None:
            row["id"] = entity.id
        return row

# Usage
db = Database.get_instance()
repo = UserRepository(db)

# Create
user = repo.create(User(email="user@example.com", name="John"))

# Read
user = repo.find_by_id(1)
users = repo.find_all(limit=10)
active_users = repo.find_by({"active": True})

# Update
user.name = "Jane"
repo.update(user)

# Delete
repo.delete(1)

Logging Configuration

from pypgkit.logging import configure_logging, LogLevel, DETAILED_FORMAT

# Basic configuration
configure_logging(level=LogLevel.INFO)

# Debug mode with detailed format
configure_logging(level=LogLevel.DEBUG, format=DETAILED_FORMAT)

# Log to file
configure_logging(level=LogLevel.INFO, filename="pypgkit.log")

# Include psycopg logs
configure_logging(level=LogLevel.DEBUG, include_psycopg=True)

Automatic Database Setup

pypgkit can automatically create the database and user if they don't exist:

from pypgkit import Database, DatabaseConfig

config = DatabaseConfig(
    database="myapp",
    user="myuser",
    password="mypassword",
)

# Interactive mode (prompts for admin credentials)
Database.init(config=config, auto_setup=True, interactive=True)

# Non-interactive mode (for CI/CD)
from pypgkit.setup import setup_database
setup_database(
    config,
    admin_user="postgres",
    admin_password="adminpass",
    interactive=False,
)

Using with Gunicorn

pypgkit automatically handles fork detection for compatibility with gunicorn:

# wsgi.py
from pypgkit import Database, DatabaseConfig

config = DatabaseConfig.from_env()
Database.init(config=config)

# The connection pool automatically resets after fork
gunicorn -w 4 myapp:app

API Reference

DatabaseConfig

Configuration dataclass for database connections.

Parameter Type Default Description
host str "localhost" Database host
port int 5432 Database port
database str "postgres" Database name
user str "postgres" Database user
password str "" Database password
connection_string str None Full connection string (optional)
min_connections int 1 Minimum pool connections
max_connections int 10 Maximum pool connections
connection_timeout float 30.0 Connection timeout in seconds
sslmode str "prefer" SSL mode
check_connection bool True Enable pool health checks
max_idle_time float 600.0 Max idle time before connection recycled

Database

Main database facade class.

Method Description
Database.init(config, schema_path, schema_sql, auto_setup, interactive) Initialize singleton
Database.get_instance() Get initialized instance
Database.is_initialized() Check if initialized
Database.reset_instance() Reset singleton (for testing)
db.connect() Establish connection
db.disconnect() Close connection pool
db.execute(query, params) Execute query, return row count
db.execute_many(query, params_seq) Execute with multiple parameter sets
db.fetch_one(query, params, as_dict) Fetch single row
db.fetch_all(query, params, as_dict) Fetch all rows
db.fetch_value(query, params) Fetch single value
db.table_exists(table_name, schema) Check if table exists
db.transaction() Context manager for transactions
db.get_stats() Get connection pool statistics
db.health_check() Check connection health

BaseRepository

Base class for repositories with CRUD operations.

Method Description
find_by_id(id) Find entity by primary key
find_all(limit, offset, order_by, order_desc) Find all entities
find_by(conditions, limit, offset, order_by, order_desc) Find by conditions
find_one_by(conditions) Find one by conditions
create(entity) Create new entity
create_many(entities) Create multiple entities
update(entity) Update existing entity
delete(id) Delete by primary key
delete_by(conditions) Delete by conditions
count(conditions) Count entities
exists(id) Check if entity exists

Development

Setup

git clone https://github.com/miichoow/PyPGKit.git
cd PyPGKit
pip install -e ".[dev]"

Running Tests

pytest tests/ -v --cov=pypgkit --cov-report=term-missing

Linting

ruff check pypgkit/
ruff format pypgkit/

License

MIT License - see LICENSE file for details.

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

pypgkit-1.0.0.tar.gz (29.4 kB view details)

Uploaded Source

Built Distribution

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

pypgkit-1.0.0-py3-none-any.whl (26.2 kB view details)

Uploaded Python 3

File details

Details for the file pypgkit-1.0.0.tar.gz.

File metadata

  • Download URL: pypgkit-1.0.0.tar.gz
  • Upload date:
  • Size: 29.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pypgkit-1.0.0.tar.gz
Algorithm Hash digest
SHA256 f3f0d460b17af9aa5de7f7c7c91b996e8528aa6e454903c83efc9c4ba933c763
MD5 434497e6e24320bcc78851baa0c9320c
BLAKE2b-256 82b20a2e062edf143d9f39d546f42e3d2c5bacaf170983c3f00bfefd8cd8e40e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypgkit-1.0.0.tar.gz:

Publisher: publish.yml on miichoow/PyPGKit

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

File details

Details for the file pypgkit-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: pypgkit-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 26.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pypgkit-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1f7e5afa9f5dc92cdaf07b0208a12702760e86ffbba15c021bbb47e6f382017b
MD5 4d7404f469b465cae25dce4b95d8a8c9
BLAKE2b-256 618c11f5be06a9e8da75cacd46a50f1f2045a5e199247b3dc89e95b1ddadf50c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypgkit-1.0.0-py3-none-any.whl:

Publisher: publish.yml on miichoow/PyPGKit

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