Postgresql fixtures and fixture factories for Pytest.
—
Comprehensive configuration system supporting command-line options, pytest.ini settings, and programmatic configuration for all aspects of PostgreSQL testing setup and behavior.
Type-safe configuration dictionary containing all PostgreSQL testing options.
class PostgresqlConfigDict(TypedDict):
"""
Typed configuration dictionary for PostgreSQL testing options.
Contains all configuration parameters with proper type annotations
for IDE support and type checking.
"""
exec: str # PostgreSQL executable path
host: str # Host address
port: Optional[str] # Port number
port_search_count: int # Port search attempts
user: str # Username
password: str # Password
options: str # Connection options
startparams: str # Server start parameters
unixsocketdir: str # Unix socket directory
dbname: str # Database name
load: List[Union[Path, str]] # Data loading paths
postgres_options: str # Postgres executable options
drop_test_database: bool # Drop database flagdef get_config(request: FixtureRequest) -> PostgresqlConfigDict:
"""
Retrieve configuration from pytest options and ini settings.
Combines command-line options and pytest.ini values to create
a complete configuration dictionary.
Parameters:
- request: pytest fixture request object
Returns:
Complete configuration dictionary with all PostgreSQL options
"""
def detect_paths(load_paths: List[Union[LocalPath, str]]) -> List[Union[Path, str]]:
"""
Convert load paths to proper Path instances.
Handles path conversion from pytest's LocalPath objects
to standard pathlib.Path objects.
Parameters:
- load_paths: List of paths in various formats
Returns:
List of normalized Path objects and strings
"""--postgresql-exec / postgresql_execstr/usr/lib/postgresql/13/bin/pg_ctl--postgresql-host / postgresql_hoststr127.0.0.1--postgresql-port / postgresql_portOptional[str]None (auto-detect)--postgresql-port-search-count / postgresql_port_search_countint5--postgresql-user / postgresql_userstrpostgres--postgresql-password / postgresql_passwordOptional[str]None--postgresql-options / postgresql_optionsstr""--postgresql-unixsocketdir / postgresql_unixsocketdirstr--postgresql-startparams / postgresql_startparamsstr"-w"--postgresql-postgres-options / postgresql_postgres_optionsstr""--postgresql-dbname / postgresql_dbnamestrtests--postgresql-load / postgresql_loadpathlist[]--postgresql-drop-test-database / postgresql_drop_test_databaseboolFalse# Basic configuration via command line
pytest --postgresql-host=localhost \
--postgresql-port=5432 \
--postgresql-user=test_user \
--postgresql-dbname=test_db
# Advanced configuration
pytest --postgresql-exec=/usr/local/bin/pg_ctl \
--postgresql-startparams="-w -t 30" \
--postgresql-options="sslmode=disable" \
--postgresql-load=/path/to/schema.sql \
--postgresql-load=/path/to/data.sql[tool:pytest]
postgresql_exec = /usr/local/bin/pg_ctl
postgresql_host = 127.0.0.1
postgresql_port = 5433
postgresql_user = test_user
postgresql_password = test_pass
postgresql_dbname = pytest_db
postgresql_options = sslmode=disable application_name=pytest
postgresql_startparams = -w -t 30
postgresql_unixsocketdir = /tmp/postgresql
postgresql_load =
/path/to/schema.sql
/path/to/fixtures.sql
postgresql_postgres_options = -c shared_preload_libraries=pg_stat_statements
postgresql_drop_test_database = falseimport pytest
from pytest_postgresql.config import get_config
def test_configuration_access(request):
"""Test accessing configuration programmatically."""
config = get_config(request)
assert config['host'] == '127.0.0.1'
assert config['user'] == 'postgres'
assert config['dbname'] == 'tests'
assert isinstance(config['port_search_count'], int)import os
from pytest_postgresql import factories
# Use environment variables for dynamic configuration
postgresql_proc = factories.postgresql_proc(
host=os.getenv('POSTGRES_HOST', '127.0.0.1'),
port=int(os.getenv('POSTGRES_PORT', '0')), # 0 for auto-detect
user=os.getenv('POSTGRES_USER', 'postgres'),
password=os.getenv('POSTGRES_PASSWORD'),
dbname=os.getenv('POSTGRES_DB', 'tests')
)from pytest_postgresql import factories
# Override specific configuration options
postgresql_custom = factories.postgresql_proc(
# Override defaults with custom values
executable='/opt/postgresql/bin/pg_ctl',
host='custom.host.com',
port=5433,
user='custom_user',
password='custom_password',
dbname='custom_db',
options='sslmode=require connect_timeout=10',
startparams='-w -t 60',
unixsocketdir='/custom/socket/dir',
postgres_options='-c log_statement=all -c log_min_duration_statement=0'
)from pytest_postgresql import factories
# Development configuration
postgresql_dev = factories.postgresql_proc(
port=5432,
dbname='dev_tests',
startparams='-w',
postgres_options='-c log_statement=none'
)
# CI configuration
postgresql_ci = factories.postgresql_proc(
port=5433,
dbname='ci_tests',
startparams='-w -t 120',
postgres_options='-c fsync=off -c synchronous_commit=off' # Faster for CI
)
# Debug configuration
postgresql_debug = factories.postgresql_proc(
port=5434,
dbname='debug_tests',
startparams='-w -t 30',
postgres_options=(
'-c log_statement=all '
'-c log_min_duration_statement=0 '
'-c log_line_prefix="%t [%p]: [%l-1] "'
)
)from pytest_postgresql.config import get_config
from pytest_postgresql.exceptions import ExecutableMissingException
import os
def test_config_validation(request):
"""Test configuration validation."""
config = get_config(request)
# Validate executable exists
if not os.path.exists(config['exec']):
raise ExecutableMissingException(f"PostgreSQL executable not found: {config['exec']}")
# Validate port range
if config['port'] and not (1024 <= int(config['port']) <= 65535):
raise ValueError(f"Invalid port number: {config['port']}")
# Validate directory exists
if not os.path.exists(config['unixsocketdir']):
os.makedirs(config['unixsocketdir'], exist_ok=True)Configuration values are resolved in the following order (highest to lowest precedence):
postgresql_proc(), etc.--postgresql-* flagspostgresql_* options in pytest.ini# pytest.ini has: postgresql_port = 5432
# Command line has: --postgresql-port=5433
# Factory has: postgresql_proc(port=5434)
# Result: port=5434 (factory parameter wins)
postgresql_proc = factories.postgresql_proc(port=5434)from pytest_postgresql.config import PostgresqlConfigDict
from typing import Optional
class CustomPostgresConfig(PostgresqlConfigDict):
"""Extended configuration with custom options."""
custom_option: str
debug_mode: bool
def get_custom_config(request) -> CustomPostgresConfig:
"""Get configuration with custom extensions."""
base_config = get_config(request)
return CustomPostgresConfig(
**base_config,
custom_option='custom_value',
debug_mode=True
)def pytest_configure(config):
"""Customize pytest-postgresql configuration."""
# Add custom defaults
if not config.getoption('postgresql_port'):
config.option.postgresql_port = '5555'
# Environment-based overrides
if os.getenv('CI'):
config.option.postgresql_startparams = '-w -t 120'Install with Tessl CLI
npx tessl i tessl/pypi-pytest-postgresql