coolguy76
coolguy76

Reputation: 20

loop attribute cannot be acessed in non-async contexts with discord.py

When I try to run this code `

import json
import os
import random
from pprint import pprint

import aiohttp
import discord
import requests
from discord.ext import commands
from dotenv import load_dotenv
from mojang import api

# Functions

# Sends a Get request to a given url
def get_info(call):
    r = requests.get(call)
    return r.json()

# Get the sum of coins in the bazaar
def get_bazaar_buy_order_value(bazaar_data):
    sum_coins = 0
    price_increase_threshold = 2
    buy_order_values = []

    # For every product
    for item_name, item_data in bazaar_data.get("products", {}).items():

        item_sum_coins = 0

        # For every buy order
        for idx, buy_order in enumerate(item_data.get("buy_summary", [])):

            # If its the best price
            if(idx == 0):
                item_expected_value = buy_order.get("pricePerUnit", 0)
                item_sum_coins += buy_order.get("amount", 0) * buy_order.get("pricePerUnit", 0)
            # If its not the best price, check for reasonable price
            else:
                if(buy_order.get("pricePerUnit", 0) < (item_expected_value * price_increase_threshold)):
                    item_sum_coins += buy_order.get("amount", 0) * buy_order.get("pricePerUnit", 0)

        buy_order_values.append((item_name, item_sum_coins))
        sum_coins += item_sum_coins

    sort_bazaar_buy_orders_by_value(buy_order_values)
    return sum_coins

# Sorts and displays a list of buy order items by total value
def sort_bazaar_buy_orders_by_value(buy_order_values):

    # Sort items by values
    buy_order_values.sort(key = lambda x: -x[1])

    # Display items and values
    for (item_name, item_sum_coins) in buy_order_values:
        print(f"{item_name.ljust(30, ' ')} | {round(item_sum_coins):,}")

    return

# Returns Bazaar data
def get_bazaar_data():
    return get_info("https://api.hypixel.net/skyblock/bazaar")

# Returns a specific item from the Bazaar
def get_bazaar_item():
    return

# Returns auction info from player uuid
def get_auctions_from_player(uuid):
    return get_info(f"https://api.hypixel.net/skyblock/auction?key={API_KEY}&player={uuid}")

# Returns current mayor/election data
def get_election_data():
    return get_info(f"https://api.hypixel.net/resources/skyblock/election")

# Returns a list of player profiles
def get_profiles_data():
    return get_info(f"https://sky.shiiyu.moe/api/v2/profile/{example_uuid}")

# Returns player UUID when prompted with the name
async def get_uuid(name):
    return get_info(f"https://sky.shiiyu.moe/api/v2/profile/{name}")

# Discord Functions / Vars

load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
GUILD = os.getenv('DISCORD_GUILD')

client = discord.Client(intents=discord.Intents.default())

intents = discord.Intents.all()

bot = commands.Bot(command_prefix='/',intents=intents)

# Hypixel Vars

Item = "Diamond"
API_FILE = open("API_KEY.json","r")
example_name = "4748"
example_uuid = "147ab344d3e54952b74a8b0fedee5534"
uuid_dashed = "147ab344-d3e5-4952-b74a-8b0fedee5534"
API_KEY = json.loads(API_FILE.read())["API_KEY"]
example_player_uuid = "147ab344d3e54952b74a8b0fedee5534"
auctions_player_url = f"https://api.hypixel.net/skyblock/auction?key={API_KEY}&player={example_player_uuid}"

# Commands

@bot.command(name='bazaar', description = "Gives a detailed readout of a certain item in the bazaar", brief = "Get data of an item in bazaar")
async def bazaar(ctx):
    await ctx.send(get_bazaar_data())
    await ctx.send(API_KEY)

@bot.command(name="bazaartotal", description = "Show the total amount of coins on the bazaar at any given point", brief = "Shows the amount of coins in the bazaar")
async def baztot(ctx):
    await ctx.send(get_bazaar_buy_order_value(get_bazaar_data()))

@bot.command(name = "apikey", description = "Gives 4748's API key, make sure to remove me once publicly availible!", brief = "API Key")
async def key(ctx):
    await ctx.send(API_KEY)

@bot.command(name = "profiles", description = 'Get a list of player profiles and data about them', brief = "List player profiles")
async def prof(ctx):
    await ctx.send("Username to check?")
    message = client.wait_for('message', check=lambda m: m.user == ctx.user)
    username = str(message.content)
    uuid = get_uuid(username)
    pprint(uuid)
    await ctx.send(uuid)
bot.run(TOKEN)

I get this error discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: loop attribute cannot be accessed in non-async contexts. Consider using either an asynchronous main function and passing it to asyncio.run or using asynchronous initialisation hooks such as Client.setup_hook Anyone have a fix for this? The bot runs normally, but once I try to run /profiles it gives me that error. Also, other commands work fine, but when I try to access an api with a

Changed my code multiple times, putting the get_uuid command in async, and googling for a few hours. any help is appreciated!

Upvotes: 0

Views: 626

Answers (2)

stijndcl
stijndcl

Reputation: 5650

Your Bot variable is called bot, but you're using client in your wait_for statement.

You've got both a discord.Client ("client") and a commands.Bot ("bot") instance. This doesn't make a whole lot of sense. If you only need Client features then use Client, if you want Bot features then use Bot. You can't use both at the same time.

Also, wait_for is a coroutine, so you should await it.

# Yours:
message = client.wait_for('message', check=lambda m: m.user == ctx.user)
#        ^^^^^^^
#        Missing await keyword & wrong bot variable

# Correct:
message = await bot.wait_for(...)
#         ^^^^^ ^^^

Docs: https://discordpy.readthedocs.io/en/stable/api.html?highlight=wait_for#discord.Client.wait_for

PS requests is blocking and will make your whole bot freeze. Consider looking into an asynchronous http library like aiohttp.

Upvotes: 1

Zloiben
Zloiben

Reputation: 1

try to do this:
message = await client.wait_for('message', check=lambda m: m.user == ctx.user)

I advise you to remove the 'name' from the slash command argument, it's better to just name the function and add an additional check for the channel 'm.channel == ctx.channel' to wait_for and split the file into several

Upvotes: 0

Related Questions