Installation

Requirements

  • Python ≥ 3.14

  • A supported async database driver (see below)

Installing OpenViper

Install from PyPI using pip:

pip install openviper

Optional Extras

OpenViper ships optional feature sets as pip extras:

Development Extras

Additional extras for contributing to OpenViper or building documentation:

Extra

Install command

Installs

dev

pip install openviper[dev]

pytest, pytest-asyncio, pytest-xdist, httpx, ruff, mypy, pylint, flake8, radon, bandit, safety, pre-commit

docs

pip install openviper[docs]

sphinx, sphinx-rtd-theme, sphinxcontrib-httpdomain

Note

The backup-db and restore-db management commands are included in the core package and do not require a separate install.

Multiple extras can be combined:

pip install openviper[postgres,tasks-redis]

Database Configuration

OpenViper uses a DATABASES dictionary in settings.py:

DATABASES = {
    "default": {
        "BACKEND": "openviper.db.backends.DefaultDatabaseBackend",
        "OPTIONS": {
            "URL": "sqlite+aiosqlite:///./db.sqlite3",
            "ECHO": False,
            "POOL_SIZE": 20,
            "MAX_OVERFLOW": 80,
            "POOL_RECYCLE": 900,
            "POOL_TIMEOUT": 10,
        },
    },
}

For PostgreSQL:

DATABASES = {
    "default": {
        "BACKEND": "openviper.db.backends.DefaultDatabaseBackend",
        "OPTIONS": {
            "URL": "postgresql+asyncpg://user:pass@localhost:5432/mydb",
            "POOL_SIZE": 20,
            "MAX_OVERFLOW": 80,
            "POOL_RECYCLE": 900,
            "POOL_TIMEOUT": 10,
            "PREPARED_STMT_CACHE": 256,
        },
    },
}

The BACKEND key is optional. When omitted, OpenViper uses the default DefaultDatabaseBackend (SQLAlchemy async engine). The short name "sqlalchemy" is also accepted as an alias for "openviper.db.backends.DefaultDatabaseBackend".

Configuration keys can be placed either inside OPTIONS (nested format) or directly in the alias dict (flat format). Both are valid:

# Nested format (recommended):
DATABASES = {
    "default": {
        "OPTIONS": {"URL": "postgresql+asyncpg://user:pass@localhost/db"},
    },
}

# Flat format (also supported):
DATABASES = {
    "default": {
        "URL": "postgresql+asyncpg://user:pass@localhost/db",
    },
}

Pool options:

Key

Default

Range

Description

POOL_SIZE

20

1-100

Number of persistent connections in the pool.

MAX_OVERFLOW

80

0-200

Additional connections allowed beyond POOL_SIZE.

POOL_RECYCLE

900

60-86400

Recycle connections after this many seconds.

POOL_TIMEOUT

10

1-300

Seconds to wait for a connection from the pool.

PREPARED_STMT_CACHE

256

0-2048

asyncpg prepared-statement cache size (PostgreSQL only).

ECHO

False

Echo all SQL statements to the log.

Supported URL formats:

Database

URL format

SQLite (dev)

sqlite+aiosqlite:///./db.sqlite3

PostgreSQL

postgresql+asyncpg://user:pass@localhost:5432/mydb

MariaDB / MySQL

mysql+aiomysql://user:pass@localhost:3306/mydb

Custom database backends can be registered by dotted path:

DATABASES = {
    "default": {
        "BACKEND": "myapp.db.MyCustomBackend",
        "OPTIONS": {"URL": "custom://host/db"},
    },
}

Message Broker Configuration

Background tasks require a message broker supported by Dramatiq. OpenViper supports Redis, RabbitMQ, Amazon SQS, and PostgreSQL.

Redis

Install Redis:

sudo apt install redis    # Linux (Debian/Ubuntu)
brew install redis        # macOS
sudo dnf install redis    # Fedora

Then set the broker and URL in settings.py:

TASKS: dict[str, Any] = dataclasses.field(
    default_factory=lambda: {
        "enabled": 1,
        "broker": "redis",
        "broker_url": os.environ.get("REDIS_URL", "redis://localhost:6379/0"),
        "backend_url": "",
        "logging": {
            "level": "INFO",
            "file": {
                "log_dir": "logs",
                "file_name": "tasks.log",
                "log_format": "json",
                "max_size": 10,
            },
            "database": {
                "task": 1,
                "periodic": 1,
            },
        },
     }
 )

RabbitMQ

Install RabbitMQ:

sudo apt install rabbitmq-server    # Linux (Debian/Ubuntu)
brew install rabbitmq              # macOS
sudo dnf install rabbitmq-server   # Fedora

Then set the broker and URL in settings.py:

TASKS: dict[str, Any] = dataclasses.field(
    default_factory=lambda: {
        "enabled": 1,
        "broker": "rabbitmq",
        "broker_url": os.environ.get("AMQP_URL", "amqp://guest:guest@localhost:5672"),
        "backend_url": "",
        "logging": {
            "level": "INFO",
            "file": {
                "log_dir": "logs",
                "file_name": "tasks.log",
                "log_format": "json",
                "max_size": 10,
            },
            "database": {
                "task": 1,
                "periodic": 1,
            },
        },
     }
 )

Note

The backend_url key enables result retrieval (e.g., fetching an actor’s return value). This currently requires a Redis URL regardless of which broker is selected.

Amazon SQS

Install the SQS extra:

pip install 'openviper[tasks-sqs]'

Configure in settings.py:

TASKS: dict[str, Any] = dataclasses.field(
    default_factory=lambda: {
        "enabled": 1,
        "broker": "sqs",
        "broker_url": "",
        "sqs_namespace": "myapp",
        "sqs_endpoint_url": os.environ.get("SQS_ENDPOINT_URL", ""),
        "backend_url": "",
        "logging": {
            "level": "INFO",
            "file": {
                "log_dir": "logs",
                "file_name": "tasks.log",
                "log_format": "json",
                "max_size": 10,
            },
            "database": {
                "task": 1,
                "periodic": 1,
            },
        },
     }
 )

Note

SQS uses AWS credentials configured via the standard boto3 credential chain (environment variables, IAM roles, etc.). Set sqs_endpoint_url to use with ElasticMQ for local development.

Stub (Testing)

The stub broker processes messages in-process without any external dependency, making it ideal for unit and integration tests. No extra package is required - it ships with Dramatiq itself.

Configure in settings.py or your test configuration:

TASKS: dict[str, Any] = dataclasses.field(
    default_factory=lambda: {
        "enabled": 1,
        "broker": "stub",
        "backend_url": "",
        "logging": {
            "level": "INFO",
            "file": {
                "log_dir": "logs",
                "file_name": "tasks.log",
                "log_format": "json",
                "max_size": 10,
            },
            "database": {
                "task": 1,
                "periodic": 1,
            },
        },
     }
 )

Note

The stub broker does not require a broker_url. It should only be used in testing environments, not in production.

Cache

Configure caching in settings.py using the CACHES dictionary:

CACHES = {
    "default": {
        "BACKEND": "openviper.cache.RedisCache",
        "OPTIONS": {"host": "localhost", "port": 6379, "db": 0},
    },
}

For local development, the default InMemoryCache requires no configuration:

CACHES = {
    "default": {
        "BACKEND": "openviper.cache.InMemoryCache",
        "OPTIONS": {"ttl": 300},
    },
}

Verifying the Installation

After installing, the openviper CLI should be available:

openviper version
# OpenViper 0.1.1

You can also verify from Python:

import openviper
print(openviper.__version__)   # 0.1.1

Development Server

OpenViper ships with Uvicorn as its ASGI server. Start the development server with either:

# Via management command (from inside a project)
python viperctl.py start-server --reload # --host 127.0.0.1 --port 8000

See also

See the Uvicorn and Gunicorn documentation for production-grade deployment configuration.

Set OPENVIPER_ENV=production before starting the server. OpenViper validates the settings at startup and rejects insecure configurations:

export OPENVIPER_ENV=production
export SECRET_KEY="$(python -c 'import secrets; print(secrets.token_urlsafe(64))')"
python viperctl.py start-server

Required production settings:

  • DEBUG must be False

  • SECRET_KEY must be set to a strong random value (>= 50 chars)

  • SECURE_COOKIES must be True

  • SECURE_SSL_REDIRECT must be True

  • SECURE_HSTS_SECONDS must be >= 31536000 (1 year)

  • SESSION_COOKIE_SECURE must be True

  • CSRF_COOKIE_SECURE must be True

  • OPENAPI["enabled"] should be False

  • CORS_ALLOWED_HEADERS must not be wildcard ("*")

If any check fails, SettingsValidationError is raised at startup.