Source code for pytest_databases.docker.postgres

from __future__ import annotations

import dataclasses
from contextlib import contextmanager
from typing import TYPE_CHECKING

import psycopg
import pytest

from pytest_databases.helpers import get_xdist_worker_num
from pytest_databases.types import ServiceContainer, XdistIsolationLevel

if TYPE_CHECKING:
    from collections.abc import Generator

    from pytest_databases._service import DockerService


def _make_connection_string(host: str, port: int, user: str, password: str, database: str) -> str:
    return f"dbname={database} user={user} host={host} port={port} password={password}"


[docs] @pytest.fixture(scope="session") def xdist_postgres_isolation_level() -> XdistIsolationLevel: return "database"
[docs] @dataclasses.dataclass class PostgresService(ServiceContainer): database: str password: str user: str
@contextmanager def _provide_postgres_service( docker_service: DockerService, image: str, name: str, xdist_postgres_isolate: XdistIsolationLevel, ) -> Generator[PostgresService, None, None]: def check(_service: ServiceContainer) -> bool: try: with psycopg.connect( _make_connection_string( host=_service.host, port=_service.port, user="postgres", password="super-secret", database="postgres", ) ) as conn: db_open = conn.execute("SELECT 1").fetchone() return bool(db_open is not None and db_open[0] == 1) except Exception: # noqa: BLE001 return False worker_num = get_xdist_worker_num() db_name = "pytest_databases" if worker_num is not None: suffix = f"_{worker_num}" if xdist_postgres_isolate == "server": name += suffix else: db_name += suffix with docker_service.run( image=image, check=check, container_port=5432, name=name, env={ "POSTGRES_PASSWORD": "super-secret", }, exec_after_start=f"psql -U postgres -d postgres -c 'CREATE DATABASE {db_name};'", transient=xdist_postgres_isolate == "server", ) as service: yield PostgresService( database=db_name, host=service.host, port=service.port, user="postgres", password="super-secret", )
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_11_service( docker_service: DockerService, xdist_postgres_isolation_level: XdistIsolationLevel, ) -> Generator[PostgresService, None, None]: with _provide_postgres_service( docker_service, image="postgres:11", name="postgres-11", xdist_postgres_isolate=xdist_postgres_isolation_level, ) as service: yield service
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_12_service( docker_service: DockerService, xdist_postgres_isolation_level: XdistIsolationLevel, ) -> Generator[PostgresService, None, None]: with _provide_postgres_service( docker_service, image="postgres:12", name="postgres-12", xdist_postgres_isolate=xdist_postgres_isolation_level, ) as service: yield service
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_13_service( docker_service: DockerService, xdist_postgres_isolation_level: XdistIsolationLevel, ) -> Generator[PostgresService, None, None]: with _provide_postgres_service( docker_service, image="postgres:13", name="postgres-13", xdist_postgres_isolate=xdist_postgres_isolation_level, ) as service: yield service
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_14_service( docker_service: DockerService, xdist_postgres_isolation_level: XdistIsolationLevel, ) -> Generator[PostgresService, None, None]: with _provide_postgres_service( docker_service, image="postgres:14", name="postgres-14", xdist_postgres_isolate=xdist_postgres_isolation_level, ) as service: yield service
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_15_service( docker_service: DockerService, xdist_postgres_isolation_level: XdistIsolationLevel, ) -> Generator[PostgresService, None, None]: with _provide_postgres_service( docker_service, image="postgres:15", name="postgres-15", xdist_postgres_isolate=xdist_postgres_isolation_level, ) as service: yield service
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_16_service( docker_service: DockerService, xdist_postgres_isolation_level: XdistIsolationLevel, ) -> Generator[PostgresService, None, None]: with _provide_postgres_service( docker_service, image="postgres:16", name="postgres-16", xdist_postgres_isolate=xdist_postgres_isolation_level, ) as service: yield service
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_17_service( docker_service: DockerService, xdist_postgres_isolation_level: XdistIsolationLevel, ) -> Generator[PostgresService, None, None]: with _provide_postgres_service( docker_service, image="postgres:17", name="postgres-17", xdist_postgres_isolate=xdist_postgres_isolation_level, ) as service: yield service
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_11_connection( postgres_11_service: PostgresService, ) -> Generator[psycopg.Connection, None, None]: with psycopg.connect( _make_connection_string( host=postgres_11_service.host, port=postgres_11_service.port, user=postgres_11_service.user, password=postgres_11_service.password, database=postgres_11_service.database, ), ) as conn: yield conn
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_12_connection( postgres_12_service: PostgresService, ) -> Generator[psycopg.Connection, None, None]: with psycopg.connect( _make_connection_string( host=postgres_12_service.host, port=postgres_12_service.port, user=postgres_12_service.user, password=postgres_12_service.password, database=postgres_12_service.database, ), ) as conn: yield conn
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_13_connection( postgres_13_service: PostgresService, ) -> Generator[psycopg.Connection, None, None]: with psycopg.connect( _make_connection_string( host=postgres_13_service.host, port=postgres_13_service.port, user=postgres_13_service.user, password=postgres_13_service.password, database=postgres_13_service.database, ), ) as conn: yield conn
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_14_connection( postgres_14_service: PostgresService, ) -> Generator[psycopg.Connection, None, None]: with psycopg.connect( _make_connection_string( host=postgres_14_service.host, port=postgres_14_service.port, user=postgres_14_service.user, password=postgres_14_service.password, database=postgres_14_service.database, ), ) as conn: yield conn
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_15_connection( postgres_15_service: PostgresService, ) -> Generator[psycopg.Connection, None, None]: with psycopg.connect( _make_connection_string( host=postgres_15_service.host, port=postgres_15_service.port, user=postgres_15_service.user, password=postgres_15_service.password, database=postgres_15_service.database, ), ) as conn: yield conn
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_16_connection( postgres_16_service: PostgresService, ) -> Generator[psycopg.Connection, None, None]: with psycopg.connect( _make_connection_string( host=postgres_16_service.host, port=postgres_16_service.port, user=postgres_16_service.user, password=postgres_16_service.password, database=postgres_16_service.database, ), ) as conn: yield conn
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_17_connection( postgres_17_service: PostgresService, ) -> Generator[psycopg.Connection, None, None]: with psycopg.connect( _make_connection_string( host=postgres_17_service.host, port=postgres_17_service.port, user=postgres_17_service.user, password=postgres_17_service.password, database=postgres_17_service.database, ), ) as conn: yield conn
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_image() -> str: return "postgres:17"
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_service( docker_service: DockerService, postgres_image: str, xdist_postgres_isolation_level: XdistIsolationLevel, ) -> Generator[PostgresService, None, None]: with _provide_postgres_service( docker_service, image=postgres_image, name="postgres", xdist_postgres_isolate=xdist_postgres_isolation_level, ) as service: yield service
[docs] @pytest.fixture(autouse=False, scope="session") def postgres_connection( postgres_service: PostgresService, ) -> Generator[psycopg.Connection, None, None]: with psycopg.connect( _make_connection_string( host=postgres_service.host, port=postgres_service.port, user=postgres_service.user, password=postgres_service.password, database=postgres_service.database, ), ) as conn: yield conn
[docs] @pytest.fixture(autouse=False, scope="session") def pgvector_image() -> str: return "pgvector/pgvector:latest"
[docs] @pytest.fixture(autouse=False, scope="session") def pgvector_service( docker_service: DockerService, pgvector_image: str, xdist_postgres_isolation_level: XdistIsolationLevel, ) -> Generator[PostgresService, None, None]: with _provide_postgres_service( docker_service, image=pgvector_image, name="pgvector", xdist_postgres_isolate=xdist_postgres_isolation_level, ) as service: yield service
[docs] @pytest.fixture(autouse=False, scope="session") def pgvector_connection( pgvector_service: PostgresService, ) -> Generator[psycopg.Connection, None, None]: with psycopg.connect( _make_connection_string( host=pgvector_service.host, port=pgvector_service.port, user=pgvector_service.user, password=pgvector_service.password, database=pgvector_service.database, ), ) as conn: yield conn