Plain is headed towards 1.0! Subscribe for development updates →

 1from __future__ import annotations
 2
 3import os
 4import subprocess
 5from typing import TYPE_CHECKING, Any
 6
 7if TYPE_CHECKING:
 8    from plain.models.backends.base.base import BaseDatabaseWrapper
 9
10
11class BaseDatabaseClient:
12    """Encapsulate backend-specific methods for opening a client shell."""
13
14    # This should be a string representing the name of the executable
15    # (e.g., "psql"). Subclasses must override this.
16    executable_name = None
17
18    def __init__(self, connection: BaseDatabaseWrapper) -> None:
19        # connection is an instance of BaseDatabaseWrapper.
20        self.connection = connection
21
22    @classmethod
23    def settings_to_cmd_args_env(
24        cls, settings_dict: dict[str, Any], parameters: list[str]
25    ) -> tuple[list[str], dict[str, str] | None]:
26        raise NotImplementedError(
27            "subclasses of BaseDatabaseClient must provide a "
28            "settings_to_cmd_args_env() method or override a runshell()."
29        )
30
31    def runshell(self, parameters: list[str]) -> None:
32        args, env = self.settings_to_cmd_args_env(
33            self.connection.settings_dict, parameters
34        )
35        env = {**os.environ, **env} if env else None
36        subprocess.run(args, env=env, check=True)