# vim: fileencoding=utf-8 # from ..template_engine import ParametersContainer from .base_format import Format, FormatError from sqlite3 import connect, Connection, OperationalError, IntegrityError import os class SqliteFormat(Format): FORMAT = 'sqlite' EXECUTABLE = True FORMAT_PARAMETERS = {'execsql'} def __init__(self, template_text: str, template_path: str, parameters: ParametersContainer = ParametersContainer(), **kwargs): self._template_text = template_text if parameters.execsql: self._mode = parameters.execsql else: self._mode = "rollback" self._executor = self.__getattribute__(f"_execute_{self._mode}") # Измененные файлы. self.changed_files = dict() # Предупреждения. self._warnings: list = [] def execute_format(self, target_path: str, chroot_path: str = '/') -> dict: '''Метод для запуска работы формата.''' if os.path.exists(target_path) and os.path.isdir(target_path): raise FormatError(f"directory on target path: {target_path}") status = "N" if os.path.exists(target_path): status = "M" connection = connect(target_path) self._executor(connection, self._template_text) connection.close() self.changed_files[target_path] = status return self.changed_files def _execute_continue(self, connection: Connection, template_text: str): """Метод для выполнения sql-команд при значения параметра execsql = continue. В этом случае после обнаружения ошибки в скрипте выполнение команд будет продолжено.""" cursor = connection.cursor() commands = template_text.split(";\n") for command in commands: try: cursor.execute(command.strip()) connection.commit() except (OperationalError, IntegrityError) as error: self._warnings.append(str(error)) def _execute_rollback(self, connection: Connection, template_text: str): """Метод для выполнения sql-команд при значения параметра execsql = rollback. В этом случае после обнаружения ошибки в скрипте результат выполнения команд будет сброшен.""" commands = template_text.split(";\n") cursor = connection.cursor() cursor.execute("BEGIN TRANSACTION;") try: for command in commands: cursor.execute(command) connection.commit() except (OperationalError, IntegrityError) as error: self._warnings.append(str(error)) connection.rollback() def _execute_stop(self, connection: Connection, template_text: str): """Метод для выполнения sql-команд при значения параметра execsql = stop. В этом случае после обнаружения ошибки в скрипте выполнение команд будет остановлено.""" cursor = connection.cursor() try: cursor.executescript(template_text) except (OperationalError, IntegrityError) as error: self._warnings.append(str(error)) finally: connection.commit() @property def warnings(self): return self._warnings