Использование pool(а) подключений к БД. Ошибка AttributeError: 'NoneType' object has no attribute 'acquire'

Есть 2 основных модуля, между которыми происходит взаимодействие:

main.py:

class Database:
   def __init__(self, dsn):
       self.dsn = dsn
       self.pool = None

   async def init(self):
       self.pool = await asyncpg.create_pool(dsn=self.dsn, command_timeout=60)

   async def query(self, arg1, arg2, arg3, arg4):
       async with self.pool.acquire() as connection:
           result = await connection.fetch("""query...""", arg1, arg2, arg3, arg4)
           return result

   async def close(self):
       await self.pool.close()

db = Database(DSN)

async def on_startup():
    # Инициализация базы данных
    await db.init()


async def on_shutdown():
    # Закрытие базы данных
    await db.close()

async def main():
    # Диспетчер
    dp = Dispatcher()
    dp.include_routers(handlers)
    await dp.start_polling(bot, on_startup=on_startup, on_shutdown=on_shutdown)

if __name__ == "__main__":
    try:
        asyncio.run(main())
        print('ON')
    except KeyboardInterrupt:
        print('OFF')

handler.py:

from main import db, Database

rt = Router()

@rt.message(Command("start"))
async def start(message: types.Message):
    try:
        arg1 = 3
        arg2 = 2
        arg3 = 1
        arg4 = 0

        sql_result = await Database.query(db, arg1, arg2, arg3, arg4)
        print(sql_result)
    except asyncpg.exceptions.UniqueViolationError:
        print("Error")

Проблема заключается в том, что при использовании команды /start в боте появляется ошибка

AttributeError: 'NoneType' object has no attribute 'acquire'

Насколько я понимаю, pool остался None, но почему, если после вызова init при старте бота pool уже не должен быть None?

При этом, без использования await здесь: sql_result = await Database.query(db, arg1, arg2, arg3, arg4) все работает, но появляется предупреждение: coroutine 'Database.query' was never awaited


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

Автор решения: AnnaBazueva

pool не был инициализирован!?

Проблема в том, что в хендлере обращаешься к классу Database а не экземпляру класса db!

@rt.message(Command("start"))
async def start(message: types.Message):
    try:
        arg1 = 3
        arg2 = 2
        arg3 = 1
        arg4 = 0

        # было так   await Database.query(db, arg1, arg2, arg3, arg4)
        sql_result = await db.query(arg1, arg2, arg3, arg4)
        print(sql_result)
    except asyncpg.exceptions.UniqueViolationError:
        print("Error")

Если обратить внимание на эту функцию:

async def on_startup():
    # Инициализация базы данных
    await db.init()  # именно для экземпляра!
→ Ссылка
Автор решения: wakaree

Проблема в том, что ты не зарегистрировал startup / shutdown обработчики, потому инициализация БД просто не вызвалась.

В aiogram 3.x это делается через регистрацию событий. Пример:

def main() -> None:
    dp = Dispatcher()
    dp.startup.register(on_startup)
    dp.shutdown.register(on_shutdown)
    return dp.run_polling()

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

→ Ссылка