python-injector / injector

Python dependency injection framework, inspired by Guice
BSD 3-Clause "New" or "Revised" License
1.32k stars 82 forks source link

AttributeError on injection #183

Closed sjosegarcia closed 3 years ago

sjosegarcia commented 3 years ago

Hello, I am getting an attribute error. I do not know if I implemented the injector correctly. What might be the cause?

line 60, in _generate_token_commands tokens = token_service.get_all_tokens() 
AttributeError: 'Binder' object has no attribute 'get_all_tokens'

bot_service.py:

from providers.token_service import TokenService
from injector import inject, singleton
from setup.config import get_settings
from schema.token_info import GenericTokenInfo
from telegram.ext import CommandHandler, MessageHandler, Filters
from telegram.ext.callbackcontext import CallbackContext
from telegram.update import Update
from telegram import ParseMode, Bot
from telegram.ext import Updater
from schema.token_info import GenericTokenInfo, TokenInfo
from telegram.ext import Updater
from loguru import logger

@singleton
class BotService:
    @inject
    def __init__(self, token_service: TokenService) -> None:
        bot = Bot(get_settings().telegram_bot_api_key)
        self.updater = Updater(bot=bot, workers=0)
        # self._process_handlers()
        logger.info(isinstance(token_service, TokenService))
        self._generate_token_commands(token_service)
        if get_settings().debug:
            self.updater.start_polling()
            self.updater.idle()

    def set_webhook(self) -> bool:
        hooked = self.updater.bot.set_webhook(
            url=f"{get_settings().telegram_bot_webhook_url}/{get_settings().telegram_bot_api_key}",
        )
        return hooked

    def main_menu(self, update: Update, context: CallbackContext) -> None:
        update.message.reply_text("Here are a list of commands available for to you!")

    def tokens(self, update: Update, context: CallbackContext) -> None:
        update.message.reply_text(
            "GODZ tokens:\n\n\tGODZ - GodZilliqa DAO token.\n\n\tGDFI - GodZilliqa DeFi token."
        )

    def whitepaper(self, update: Update, context: CallbackContext) -> None:
        update.message.reply_text("Whitepaper can be found here:")

    def new_member(self, update: Update, context: CallbackContext) -> None:
        for member in update.message.new_chat_members:
            if not member.is_bot:
                update.message.reply_text("Welcome to GodZilliqa DeFi,")

    def unknown(self, update: Update, context: CallbackContext) -> None:
        context.bot.send_message(
            chat_id=update.effective_chat.id,
            text="Use /start to find a list of commands.",
        )

    def _generate_token_commands(
        self,
        token_service: TokenService,
    ) -> None:
        tokens = token_service.get_all_tokens()
        for token in tokens:
            price = token_service.get_token_info(token.symbol)
            self._register_token_command(token, price)

    def _register_token_command(
        self, token: GenericTokenInfo, price: TokenInfo
    ) -> None:
        token_website = (
            f"\n<a href='{token.website}'>Website</a>" if token.website else ""
        )
        token_whitepaper = (
            f"\n<a href='{token.whitepaper}'>Whitepaper</a>" if token.whitepaper else ""
        )
        token_address = (
            f"\n<a href='https://viewblock.io/zilliqa/address/{token.address_bech32}'>{token.symbol} contract on viewblock.io</a>"
            if token.address_bech32
            else ""
        )
        token_zilstream = f"\n<a href='https://zilstream.com/tokens/{token.symbol}'>View {token.symbol} on zilstream.com</a>"
        token_price = f"\n<b>{price.rate:.2f} ZIL - ${price.rate_usd:.2f}</b>"
        token_info = (
            f"<b>{token.name} ({token.symbol})\nScore: {token.viewblock_score}/100</b>"
        )

        self.updater.dispatcher.add_handler(
            CommandHandler(
                token.symbol.lower(),
                lambda update, context: update.message.reply_text(
                    f"{token_info}{token_price}{token_website}{token_whitepaper}{token_address}{token_zilstream}",
                    parse_mode=ParseMode.HTML,
                    disable_notification=True,
                    disable_web_page_preview=True,
                    allow_sending_without_reply=True,
                ),
            )
        )

    def _process_handlers(self) -> None:
        self.updater.dispatcher.add_handler(CommandHandler("menu", self.main_menu))
        self.updater.dispatcher.add_handler(CommandHandler("tokens", self.tokens))
        self.updater.dispatcher.add_handler(
            CommandHandler("whitepaper", self.whitepaper)
        )
        self.updater.dispatcher.add_handler(
            MessageHandler(Filters.status_update.new_chat_members, self.new_member)
        )
        self.updater.dispatcher.add_handler(
            MessageHandler(Filters.command, self.unknown)
        )

token_service.py

from schema.token_info import TokenInfo, GenericTokenInfo
from httpx import get
from setup.config import get_settings
from fastapi import HTTPException, status
from injector import singleton

@singleton
class TokenService:
    def get_token_info(self, token: str) -> TokenInfo:
        response = get(f"{get_settings().zilstream_token_url}/{token}")
        if response.status_code == status.HTTP_404_NOT_FOUND:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"There is no data available for the specified token you requested. {response.json()}",
            )
        return TokenInfo(**response.json())

    def get_all_tokens(self) -> list[GenericTokenInfo]:
        response = get(f"{get_settings().zilstream_token_url}")
        if response.status_code == status.HTTP_404_NOT_FOUND:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"There was an error retreiving the list of available token data. {response.json()}",
            )
        data = response.json()
        tokens = [GenericTokenInfo(**token_data) for token_data in data]
        return tokens
jstasiak commented 3 years ago

Hey, please provide the versions of the software you're running (Python, Injector), a complete stack trace and the code used to configure injector (with all the relevant modules). If you could provide a minimal test case to reproduce this it'd be ideal, otherwise it may be difficult to figure out what's wrong.

sjosegarcia commented 3 years ago

I figured it out. Closing now.