discord.py discord_components interaction failed - python

I wanted to make a discord bot and one of his features is shop,
for shop menu I used discord components, It loops to a items file made in yaml and then append to a list in python, then make a embed message with that item and his options, with buttons for forward and back, when I click them they work but it take a while until they update and I receive "This interaction failed"
CODE:
with open('items.yaml', 'r') as yaml_file:
item_list_yaml = yaml.safe_load(yaml_file)
items = []
shop_items = []
for item in item_list_yaml:
items.append(item)
for item in items:
new_item_listed = {
'name':item_list_yaml[f'{item}']['name'],
'buy_price':item_list_yaml[f'{item}']['buy_price'],
'amount':item_list_yaml[f'{item}']['amount'],
'sell_price':item_list_yaml[f'{item}']['sell_price'],
'item_id':item_list_yaml[f'{item}']['item_id'],
'emoji':item_list_yaml[f'{item}']['emoji'],
}
copy = new_item_listed.copy()
shop_items.append(copy)
class Shop(commands.Cog):
def __init__(self, client):
self.client = client
self.cluster = MongoClient(DB)
cluster = MongoClient(DB)
self.collection = cluster.users.eco
DiscordComponents(client)
#commands.command(
name = "shop"
)
async def main_shop(self, ctx):
global position_in_shop_items
position_in_shop_items = 0
max_position_in_shop_items = len(shop_items)
def get_buttons(x, y, z):
if x == 0:
label = "->"
elif x == y:
label = "<-"
else:
if z == 1:
label = "->"
elif z == 3:
label = "<-"
return label
while True:
start_component = ([Button(style=ButtonStyle.grey, label="->"), Button(style=ButtonStyle.grey, label="<-")])
item = shop_items[position_in_shop_items]
if item['sell_price'] is None:
embed = discord.Embed(
title = "Shop",
description = f"""
{item['emoji']}**{item['name']}**
**Buy Price: `{item['buy_price']}`<:coins:872444592115568661>**
"""
)
elif item['buy_price'] is None:
embed = discord.Embed(
title = "Shop",
description = f"""
{item['emoji']}**{item['name']}**
**Sell Price: `{item['sell_price']}`<:coins:872444592115568661>**
"""
)
else:
embed = discord.Embed(
title = "Shop",
description = f"""
{item['emoji']}**{item['name']}**
**Buy Price: `{item['buy_price']}`<:coins:872444592115568661>**
**Sell Price: `{item['sell_price']}`<:coins:872444592115568661>**
"""
)
if position_in_shop_items == 0:
temp = await ctx.send(embed=embed, components = [Button(style=ButtonStyle.grey, label=get_buttons(position_in_shop_items, max_position_in_shop_items, 1))])
elif position_in_shop_items == max_position_in_shop_items:
try:
await temp.edit(embed=embed, components = [Button(style=ButtonStyle.grey, label=get_buttons(position_in_shop_items, max_position_in_shop_items, 3))])
except:
pass
else:
try:
await temp.edit(embed=embed, components = [[Button(style=ButtonStyle.grey, label="<-"), Button(style=ButtonStyle.grey, label="->")]])
except:
pass
response = await self.client.wait_for("button_click")
if response.component.label == "->":
position_in_shop_items +=1
elif response.component.label == "<-":
position_in_shop_items -=1

Discord expects a response to the created interaction, with discord components this is materialized by the Interaction.respond() method which is documented here.
You have several response methods, but if you just don't want to do anything, put 6 for the type parameter.
If you want to do something else, there are other possibilities documented here.

Related

Discord.py V2 Giveaway Command Not Working

I am making a discord.py giveaway command. It puts the winners into the list 'winners' and then it's supposed to announce them. My issue is that I can print the winners to the terminal but I can't get the bot to mention the winners in the message it sends.
This is the code I am using:
#commands.hybrid_command(name='startgive')
#commands.has_permissions(administrator=True)
async def startgive(self, ctx: commands.Context, prize: str, duration: str, total_winners: int, *, channel: discord.TextChannel):
await ctx.send(f"Giveaway created in <#{channel.id}> for {prize}, and will last {duration}.")
duration_seconds = convert(duration)
embed = discord.Embed(title = f"{prize} Giveaway!", color = ctx.author.color)
embed.add_field(name='Ends', value=f"{duration}", inline = False)
embed.add_field(name = "Hosted by:", value = ctx.author.mention, inline = False)
embed.add_field(name='Winners', value=f"{total_winners}", inline = False)
my_msg = await channel.send(embed = embed)
await my_msg.add_reaction("🎉")
await asyncio.sleep(duration_seconds)
new_msg = await channel.fetch_message(my_msg.id)
users = []
for reaction in new_msg.reactions:
if reaction.emoji == '🎉':
async for user in reaction.users():
if user != self.bot.user:
users.append(user.mention)
if len(users) < total_winners:
winners_number = len(users)
else:
winners_number = total_winners
winners = []
for i in range(winners_number):
user = random.randint(0, winners_number)
if users[user] not in winners:
winners.append(users[user])
print(', '.join(winners)) #This line is used to simply show that the winners array does hold a value of a user being mentioned
updatedEmbed = discord.Embed(title = f"{prize} Giveaway!", color = ctx.author.color)
updatedEmbed.add_field(name = "Hosted by:", value = ctx.author.mention, inline = False)
updatedEmbed.add_field(name = "Winners:", value = f"{', '.join(winners)}", inline = False)
updatedEmbed.set_footer(text = f"Ended", inline = False)
await my_msg.edit(embed=updatedEmbed)
await channel.send(f"Congratulations! {', '.join(winners)} won {prize}! Thank you for participating.")
def convert(time):
pos = ["s","m","h","d"]
time_dict = {"s" : 1, "m" : 60, "h" : 3600 , "d" : 3600*24}
unit = time[-1]
if unit not in pos:
return -1
try:
val = int(time[:-1])
except:
return -2
return val * time_dict[unit]

I am trying to make a use system for my discord bot (py), but it does not work

I am trying to make an economy system for my discord servers with discord.py but I cannot find any system to use an object which is stored in an inventory in .JSON. I would like that when we call the function use, for example, it removes an object from my inventory, and if this object is not in my inventory, it tells me that I do not have it.
My code:
#bot.command()
async def use(ctx, item, amount = -1,):
await open_account(ctx.author)
res = await use_this(ctx.author,item,amount)
if item <= 0 in
if not res[0]:
if res[1]==1:
await ctx.send("That Object isn't there!")
return
if res[1]==2:
await ctx.send(f"Vous n'avez pas cette objet{amount} {item}")
return
await ctx.send(f"You use 1 {item}")
async def use_this(user,item_name,amount):
item_name = item_name.lower()
name_ = None
for item in mainshop:
name = item["name"].lower()
if name == item_name:
name_ = name
price = item["price"]
break
if name_ == None:
return [False,1]
cost = price*amount
users = await get_bank_data()
bal = await update_bank(user)
if bal[0]<cost:
return [False,2]
try:
index = 0
t = None
for thing in users[str(user.id)]["inv"]:
n = thing["item"]
if n == item_name:
old_amt = thing["amount"]
new_amt = old_amt + amount
users[str(user.id)]["inv"][index]["amount"] = new_amt
t = 1
break
index+=1
if t == None:
obj = {"item":item_name , "amount" : amount}
users[str(user.id)]["inv"].append(obj)
except:
obj = {"item":item_name , "amount" : amount}
users[str(user.id)]["inv"] = [obj]
with open("mainbank.json","w") as f:
json.dump(users,f)
return [True,"Worked"]

why does it keep saying "TypeError: '<=' not supported between instances of 'int' and 'str'"?

this is the full error of the code
i would really love the help
mainshop = [{"name":"Time_watch","price":1000,"description":"Resets certain cooldowns (limited uses)(WIP)"}, {"name":"Gun","price":10000,"description":"A better way to rob people with a shorter cooldown!"}, {"name":"Guhhh Placeholder!!","price":10000000,"description":"I sure love placeholders"}]
#client.command()
#commands.is_owner()
async def shop(ctx):#real#:troll:.name
em = discord.Embed(title = "Shopping District")
for item in mainshop:
name = item["name"]
price = item["price"]
desc = item["description"] #i do believe its because you have like no DESCRIPTION in the item list thing
#get fake
em.add_field(name = name, value = f"${price} | {desc}")
#real
await ctx.send(embed = em)
import discord
from discord.ext import commands
import asyncio
import os
import json
##### START LEVEL COMMAND #####
#client.command(name='bal')
async def balance(ctx, user:discord.Member=None):
colour = randint(0, 0xffffff)
await open_account(ctx.author)
if user is None:
user = ctx.author
users = await get_bank_data()
wallet_amt = users[str(user.id)]["wallet"]
bank_amt = users[str(user.id)]["bank"]
em = discord.Embed(title=f"{user}'s balance", color=colour)
em.add_field(name="Wallet", value=wallet_amt)
em.add_field(name="Bank", value=bank_amt)
await ctx.send(embed=em)
async def buy_this(user,item_name,amount):
item_name = item_name.lower()
name_ = None
for item in mainshop:
name = item["name"].lower()
if name == item_name:
name_ = name
price = item["price"]
break
if name_ == None:
return [False,1]
cost = price*amount
users = await get_bank_data()
bal = await update_bank(user)#r.i.p. KB's confindince
if bal[0]<= cost:
return [False,2]
try:
index = 0
t = None
for thing in users[str(user.id)]["bag"]:
n = thing["item"]
if n == item_name:
old_amt = thing["amount"]
new_amt = old_amt + amount
users[str(user.id)]["bag"][index]["amount"] = new_amt
t = 1
break
index+=1
if t == None:
obj = {"item":item_name , "amount" : amount}
users[str(user.id)]["bag"].append(obj)
except:
obj = {"item":item_name , "amount" : amount}
users[str(user.id)]["bag"] = [obj]
with open("mainbank.json","w") as f:
json.dump(users,f)
await update_bank(user,cost*-1,"wallet")
return [True,"Worked"]
#client.command()
async def buy(ctx,item,amount):#how come these arent definded no more? oh I prollydid smth by mistake guhhhhhhh
res = await buy_this(ctx.author,item,amount)
if not res[0]:
if res[1]==1:
await ctx.send("That is not an item in shop")
return
if res[1]==2:
await ctx.send(f"You don't have enough money to buy the {amount}")
return
await ctx.send(f"Successfully bought {amount}: {item}")
#client.command()
#commands.is_owner()
async def bag(ctx):
await open_account(ctx.author)
user = ctx.author
users = await get_bank_data()
try:
bag = users[str(user.id)]["bag"]
except:
bag = []
em = discord.Embed(title = "Bag")
for item in bag:
name = item["item"]
amount = item["amount"]
em.add_field(name = name, value = amount)
await ctx.send(embed = em)
#Oh you mean this ? oh yeah Idk what I put that there
async def open_account(user):
users = await get_bank_data()
if str(user.id) in users:
return False
else:
users[str(user.id)] = {}
users[str(user.id)]["wallet"] = 0
users[str(user.id)]["bank"] = 0
with open("mainbank.json", "w") as f:
json.dump(users, f)
return True
async def get_bank_data():
with open("mainbank.json", "r") as f:
users = json.load(f)
return users
async def update_bank(user, change=0, mode="wallet"):
users = await get_bank_data()
users[str(user.id)][mode] += change
with open("mainbank.json", "w") as f:
json.dump(users, f)
bal = [users[str(user.id)]["wallet"], users[str(user.id)]["bank"]]
return bal
the code that should matter. I do not understand at all what is wrong with the code. I used this code before no errors. So if anyone could please explain that would be greatly appreciated. I have tried putting this in its own thing. it didnt work still. i have also tried putting if bal <= int(cost) this also didnt work.
on the line if bal[0]<= cost: if you cast to an integer int(bal[0]) it should be comparing two integers then, and vice-versa if cost is a string
Cost is already an int, looks like bal[0] is a string. Try int(bal[0]) <= cost instead (or float(bal[0]) if it has decimals)

How can I make top 10 command work, where it grabs the top 10 in the JSON?

Here's my current code:
import discord
from discord.ext import commands
class Fun:
def __init__(self, client):
self.client = client
#commands.command(aliases=["lb"], pass_context=True)
async def leaderboard(self, ctx):
experience = self.getexperience()
with open('users.json') as f:
data = json.load(f)
lines = sorted(data.items(), key=operator.itemgetter(1), reverse=True) # sorts lines by balance
lb = [] # leaderboard
for line in lines: # each line in file
user = self.bot.get_user(id=int(line[0])) # grab user object from ID
if not user:
user = await self.bot.fetch_user(int(line[0]))
lb.append(f"{user.name} | {format(line[1], ',d')} {experience}\n") # add username and balance to leaderboard
limitedMsgs = [] # array for each page
pageCount = math.ceil(len(lb) / 10) # pageCount = number of users / 10 users per page
for x in range(0, pageCount): # for every page
limitedMsgs.append("".join(lb[x*10:x*10+10])) # add those 10 users to 1 page
currPage = 0
embed = discord.Embed(color=0xdfe324, description=limitedMsgs[0])
embed.set_footer(text=f"Page: {currPage + 1} of {pageCount}")
msg = await self.client.say(embed=embed)
def check(reaction, user):
return (user == ctx.message.author) and (str(reaction.emoji) == '⬅' or str(reaction.emoji) == '➡')
while(True):
if pageCount > 1:
if currPage == 0: # if first page
await msg.add_reaction("âž¡")
print(pageCount)
elif (currPage + 1) == pageCount: # if last page
await msg.add_reaction("⬅")
else: # if not first nor last
await msg.add_reaction("âž¡")
await msg.add_reaction("⬅")
try:
reaction, user = await self.bot.wait_for('reaction_add', timeout=60, check=check) # wait for user reaction
except asyncio.TimeoutError:
break # end while loop if no user reaction
if str(reaction.emoji) == '⬅':
currPage = currPage - 1
if str(reaction.emoji) == 'âž¡':
currPage = currPage + 1
embed = discord.Embed(color=0xdfe324, description=limitedMsgs[currPage])
embed.set_footer(text=f"Page: {currPage + 1} of {pageCount}")
await msg.clear_reactions()
await msg.edit(embed=embed)
await msg.clear_reactions() # clear reactions after while loop
def setup(client):
client.add_cog(Fun(client))
heres the error:
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'Fun' object has no attribute 'getexperience'
Like I said before, I want it to grab the top 10 in the JSON, then order it into first to last but I'm stuck on this part. Most of this code is done; it's just the grabbing of the xp from the JSON. Any help would be appreciated. Thanks.
The error seems to be because of the line experience = self.getexperience(), as the full traceback should have pointed out. Your class/cog doesn't have the method, getexperience.

how to keep a discord bot from randomly breaking

I have a discord bot, it runs a set program when called. After there is any error in the program, if it is called again after that it will randomly keep values from the last usage or respond to itself breaking the code once again. here is the code.
from planetlists import planet_cap,planet_lvl,transfer,temp,credit_per_hour,planet_cost,max_levels_planet
import time
import discord
import asyncio
style.use("fivethirtyeight")
client = discord.Client()
TOKEN = '-----------------'
async def get_input_of_type(func):
while True:
try:
msg = await client.wait_for('message')
return func(msg.content)
except ValueError:
continue
#client.event # event decorator/wrapper
async def on_ready():
global sentdex_guild
print(f"We have logged in as {client.user}")
#client.event
async def on_message(message):
global sentdex_guild
print(f"{message.channel}: {message.author}: {message.author.name}: {message.content}")
if "hadescalc.logout()" == message.content.lower():
await client.close()
elif "hadescalc.planet()" == message.content.lower():
await message.channel.send("What is the first number?")
firstnum = await get_input_of_type(int)
firstnum = firstnum + 3
await message.channel.send("What is the second number?")
secondnum = await get_input_of_type(int)
await message.channel.send(f"{firstnum} + {secondnum} = {firstnum+secondnum}")
elif message.content.startswith('$planet_cap'):
channel = message.channel
try:
class Planet:
def __init__(self,level = 0,storage = 0,credit_per_hour = 0,cost = 0,types = 'desert',tier = 1):
self.level = level
self.storage = storage
self.credit_per_hour = credit_per_hour
self.cost = cost
self.types = types
self.tier = tier
def __str__ (self):
return ('level: '+ self.level + ', storage cap: ' + self.storage + ', credits per hour: ' + self.credit_per_hour + ', cost to upgrade: ' + self.cost + ', Planet type: ' + self.types + ', planet tier: ' + self.tier)
def set_planet_lvl(self,level):
self.level = level
def get_planet_lvl(self):
return(self.level)
def set_planet_cost(self,cost):
self.cost = cost
def get_planet_cost(self):
return(self.cost)
def set_planet_storage(self,storage):
self.storage = storage
def get_planet_storage(self):
return(self.storage)
def set_planet_credit_per_hour(self,credit_per_hour):
self.credit_per_hour = credit_per_hour
def get_planet_credit_per_hour(self):
return(self.credit_per_hour)
def get_planet_types(self):
return(self.types)
def get_planet_tier(self):
return(self.tier)
planet_list = {}
await channel.send('how many planets do you have?')
number = await get_input_of_type(int)
await channel.send('for planet type, choose from desert,fire,water,terran,gas, and ice\n ')
await channel.send('for planet tier you can only do the folowing...\n \ndesert- 1,3,4\nfire- 1,3,4\nwater- 1,3,4\nterrran- 1,3,4\ngas- 2,4\nice- 4')
for i in range(number):
await channel.send('level for the {} planet: '.format(i+1))
levels = await get_input_of_type(str)
print(levels)
credit_cap = planet_cap(levels)
print(credit_cap)
await channel.send('planet type for the {} planet: '.format(i+1))
planet_type = await get_input_of_type(str)
await channel.send('planet tier for the {} planet: '.format(i+1))
teirlvl = await get_input_of_type(str)
credits_per_hour = credit_per_hour(planet_type,levels,teirlvl)
cost = planet_cost(levels)
planet_list[i] = (Planet(levels,credit_cap,credits_per_hour,cost,planet_type,teirlvl))
orig_planet_lvl = []
for i in planet_list:
orig_planet_lvl.append(planet_list[i].get_planet_lvl())
cost_list = []
increase_in_cap = []
increase_in_income = []
decider = []
temp_planets = planet_list.copy()
current_storage = 0
for i in temp_planets:
storage = int(temp_planets[i].get_planet_storage())
print(storage)
current_storage += storage
await channel.send(('Your starting storage is: ',current_storage))
await channel.send('what is your credit cap goal: ')
cap_goal = await get_input_of_type(int)
max_levels = []
for i in planet_list:
max_levels.append(max_levels_planet(temp_planets[i].get_planet_types(),temp_planets[i].get_planet_tier()))
while cap_goal >= current_storage:
for i in temp_planets:
storage = temp_planets[i].get_planet_storage()
planet_lvl = temp_planets[i].get_planet_lvl()
credit_per_hours = temp_planets[i].get_planet_credit_per_hour()
planet_type = temp_planets[i].get_planet_types()
planet_tier = temp_planets[i].get_planet_tier()
new_lvl = str((int(planet_lvl) + 1))
if planet_lvl == max_levels[i]:
cost_list.append(temp_planets[i].get_planet_cost())
increase_in_cap.append('99999')
increase_in_income.append('99999')
decider.append('99')
else:
cost_list.append(temp_planets[i].get_planet_cost())
increase_cap = int(planet_cap(new_lvl))- int(storage)
if increase_cap == 0:
increase_cap = 1
increase_in_cap.append(increase_cap)
new_credits_per_hour = credit_per_hour(planet_type,new_lvl,planet_tier)
increase_in_incomees = (str(int(new_credits_per_hour)-int(credit_per_hours)))
if increase_in_incomees == 0:
increase_in_incomees = 1
increase_in_income.append(increase_in_incomees)
decider.append(str((int(cost_list[i])/int(increase_in_cap[i])/ int(increase_in_income[i]))))
value = min(decider)
first = ''
for index,item in enumerate(decider):
if item == value:
if first == '':
await channel.send(('planet',(index +1), '--->', (int(temp_planets[index].get_planet_lvl())+1)))
temp_planets[index].set_planet_lvl(str(int(temp_planets[index].get_planet_lvl())+1))
temp_planets[index].set_planet_cost(str(planet_cost(str(temp_planets[index].get_planet_lvl()))))
temp_planets[index].set_planet_storage(str(planet_cost(str(temp_planets[index].get_planet_lvl()))))
temp_planets[index].set_planet_credit_per_hour(str(credit_per_hour(temp_planets[index].get_planet_types(),temp_planets[index].get_planet_lvl(),temp_planets[index].get_planet_tier())))
current_storage += int(temp_planets[index].get_planet_storage())
first = '1'
cost_list = []
increase_in_cap = []
increase_in_income = []
decider = []
await channel.send('Your storage went up to: {} '.format(current_storage))
await channel.send('Your final storage is: {}'.format(current_storage))
for index,item in enumerate(planet_list):
await channel.send(('{} planet whent from lvl'.format(index+1),orig_planet_lvl[index], 'to lvl',temp_planets[index].get_planet_lvl()))
except (Exception, ValueError) as e:
print(str(e))
client.run(TOKEN)
it waits for user input and if you enter something wrong it just breaks completely, i have tried to use try and except blocks but it wont recognize it either (I could be using it wrong).If anyone has a solution or something that would be great!
Your code is too messy to understand what you want to do. I recommend you to clean up your code first, and rewrite the question. Followings are the problems your code has.
1
Use check instead of get_input_of_type(). Maybe get_input_of_type() works fine, but there already exists a function to check user message input. Your code seems to use this many times, so it is good to define a function for the shorter code.
def is_number(msg):
return msg.content.isdigit()
#client.event
async def on_message(message):
if "hadescalc.planet()" == message.content.lower():
await client.send_message("What is the first number?")
firstnumber = await client.wait_for_message(
author=message.author,
channel=message.channel,
check=is_number)
firstnumber += 3
await client.send_message("What is the second number?")
secondnumber = await client.wait_for_message(
author=message.author,
channel=message.channel,
check=is_number)
await client.send_message("{} + {} = {}".format(
firstnumber, secondnumber, firstnumber+secondnumber))
2
Don't define class in a function. It is better to define Planet out of on_message. And instead of set_*** and get_***, use #property and #setter.
class Planet:
def __init__(self, level, ___):
self._level = level
# blah
pass
#property
def level(self):
return self._level
#level.setter
def level(self, new_level):
self._level = new_level
3
You are casting int and str too many times, but this is not good. For example, **_lvl values are all int and no need to cast str. Remove all the unnecessary type casting. Also, i cannot understand what decider does, but it may not works as you want. decider is a list of str(all int in fact), so min(decider) finds alphabetical min value not the numeric min value. If you change **_lvl into int type, it will returns numeric min value as expected.

Categories

Resources