@Maxwell012

Как вызвать асинхронный декоратор с дочернего класса?

Я пытался вынести декоратор в дочерний класс для улучшения кода, но с этого ничего не выходит. Вот собственно мой класс с декоратором:
class CacheCityManager(Geocoder):

    @staticmethod
    async def save_data(data) -> bool:
        return await db.add_city(**data)

    @staticmethod
    async def get_data(city: str) -> dict:
        result = await db.get_city(city=city)
        return result if result else {}

    def cache(self, func):
        async def wrapper(*args, **kwargs) -> Optional[dict]:
            func_name = func.__name__
            city = args[0] if args else kwargs['city']
            city = city.lower()
            data = await self.get_data(city)

            if data:
                print(f"The city {city} were found in the cache")
                return data
            else:
                try:
                    data = await func(*args, **kwargs)
                    await self.save_data(data)
                    return data
                except Exception as ex:
                    self.logger.error(f"{func_name.upper()} error (args={args}, kwargs={kwargs}): {ex}", exc_info=True)
                    return None
        return wrapper

и как я его вызываю:
class Geocoder:
    @staticmethod
    def cache(func):
        pass

    @cache
    async def get_info_city_via_name(self, city: str) -> Optional[dict]:
        data = await self._request_for_geocoding(geocode=city)
        if data:
            print("got info from yandex geocoder: ", data)
            city_coordinates = data['response']['GeoObjectCollection']['featureMember'][0]['GeoObject']['Point']['pos']
            city_coordinates = await self._get_city_coordinates(coordinates=city_coordinates)

            collection = data['response']['GeoObjectCollection']
            components = (
                collection['featureMember'][0]['GeoObject']['metaDataProperty']['GeocoderMetaData']['Address']
                ['Components']
            )
            city_en = [component['name'] for component in components if component['kind'] == 'locality'][0]
            timezone, utc_offset = await self.get_time_zone(city=city_en)
            return {"city": city, "city_coordinates": city_coordinates, "timezone": timezone, "utc_offset": utc_offset}

Я хотел вынести декоратор который кеширует данные в дочерний класс но вызывать его все также с родительского класса, создал метод кеш в родительском классе который будет переназначаться в дочернем классе, но к сожалению при попытке вызова метода get_info_city_via_name я получаю ошибку:
Cause exception while process update id=56412018 by bot id=6663434503
TypeError: 'NoneType' object is not callable
Traceback (most recent call last):
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/dispatcher.py", line 308, in _process_update
    response = await self.feed_update(bot, update, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/dispatcher.py", line 157, in feed_update
    response = await self.update.wrap_outer_middleware(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/middlewares/error.py", line 25, in __call__
    return await handler(event, data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/middlewares/user_context.py", line 27, in __call__
    return await handler(event, data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/fsm/middleware.py", line 41, in __call__
    return await handler(event, data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/event/telegram.py", line 120, in trigger
    return await wrapped_inner(event, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/event/handler.py", line 42, in call
    return await wrapped()
           ^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/dispatcher.py", line 275, in _listen_update
    return await self.propagate_event(update_type=update_type, event=event, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/router.py", line 116, in propagate_event
    return await observer.wrap_outer_middleware(_wrapped, event=event, data=kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/router.py", line 111, in _wrapped
    return await self._propagate_event(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/router.py", line 136, in _propagate_event
    response = await observer.trigger(event, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/event/telegram.py", line 120, in trigger
    return await wrapped_inner(event, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.11/site-packages/aiogram/dispatcher/event/handler.py", line 42, in call
    return await wrapped()
           ^^^^^^^^^^^^^^^
  File "/src/handlers/classes/Profile.py", line 352, in get_city_user
    result = await self.get_city(message=message, state=state)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/src/handlers/classes/Profile.py", line 134, in get_city
    city_info = await self.geocoder.get_info_city_via_name(city=city)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'NoneType' object is not callable
  • Вопрос задан
  • 82 просмотра
Пригласить эксперта
Ответы на вопрос 1
fenrir1121
@fenrir1121
Начни с документации
Как вызвать асинхронный декоратор с дочернего класса?
Никак.

Вы слышали про инкапсуляцию? Методы которые Вы определяете в классе, доступны только для объектов этого класса и наследников. У вас все наоборот: метод объявлен в потомке, а вызвать пытаетесь из родителя.
Вообще исходя из того что у вас в классе 2 статик метода и недодекоратор создается ощущение, что вы делаете что-то не то. Да и причин в наследовании что-то не вижу.

А декоратор просто сделайте отдельно. Если очень любите классы, можно реализовать декоратор на основе класса поместив логику в __call__
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы