Как задекорировать read-only метод класса?

Описание проблемы

Есть модуль cx-Oracle. Я хотел задекорировать метод execute класса Cursor, чтобы он логировал выполняемые запросы:

import logging


class _QueryLogger:
    def __init__(self, execute_func):
        self._func = execute_func
        self._logger = logging.getLogger()

    def __call__(self, query: str):
        self._logger.log(level=logging.DEBUG, msg=query)
        return self._func(query)

Затем через контекстный менеджер возвращать объект курсора с задекорированным методом execute:

import cx_Oracle
from credentials import credentials
from deco import _QueryLogger


class DbOracle:
    @contextmanager
    def _get_cursor(self):
        with cx_Oracle.Connection(**credentials) as conn:
            cursor = conn.cursor()
            cursor.execute = _QueryLogger(cursor.execute)  # Проблема здесь
            yield cursor

    def execute(self, query):
        with self._get_cursor() as cursor:
            cursor.execute(query)

При пользовании этим:

oracle = DbOracle()
oracle.execute("select * from v$version")

Возникает исключение:

AttributeError: 'cx_Oracle.Cursor' object attribute 'execute' is read-only

Вопрос

Как это можно обойти? Хотелось бы добавить логирование к самому объекту курсора, через который выполняются запросы.

Зачем

В классе DbOracle предполагается несколько методов для выполнения различных SQL запросов. Прикрутить логирование к объекту курсора я хочу затем, чтобы в каждом из этих методов не логировать запрос перед тем, как его исполнить (читай, избежать дублирования кода).


Ответы (1 шт):

Автор решения: Михаил Муругов

В приведенном в вопросе классе DbOracle определен метод def execute(self, query): - почему бы туда логгирование не засунуть? © mrEvgenX

Это оказалось рациональным решением.

→ Ссылка