AttributeError: 'Context' object has no attribute 'guild_icon' - discord

I am trying to set up a command to print the information of the server the bot is in. The code below gives the error AttributeError: 'Context' object has no attribute 'guild_icon'
#commands.command()
async def serverinfo(self,ctx):
name = str(ctx.guild.name)
description = str(ctx.guild.description)
owner = str(ctx.guild.owner)
id = str(ctx.guild.id)
region = str(ctx.guild.region)
memberCount = str(ctx.guild.member_count)
embed = discord.Embed(
title=name + " Server Information",
description=description,
color=discord.Color.blue()
)
embed.set_thumbnail(ctx.guild_icon)
embed.add_field(name="Owner", value=owner, inline=True)
embed.add_field(name="Server ID", value=id, inline=True)
embed.add_field(name="Region", value=region, inline=True)
embed.add_field(name="Member Count", value=memberCount, inline=True)
await ctx.send(embed=embed)
When trying to find the solution I tried to change the code to be
#commands.command()
async def serverinfo(self,ctx):
name = str(ctx.guild.name)
description = str(ctx.guild.description)
owner = str(ctx.guild.owner)
id = str(ctx.guild.id)
region = str(ctx.guild.region)
memberCount = str(ctx.guild.member_count)
embed = discord.Embed(
title=name + " Server Information",
description=description,
color=discord.Color.blue()
)
embed.set_thumbnail(ctx.guild.icon)
embed.add_field(name="Owner", value=owner, inline=True)
embed.add_field(name="Server ID", value=id, inline=True)
embed.add_field(name="Region", value=region, inline=True)
embed.add_field(name="Member Count", value=memberCount, inline=True)
await ctx.send(embed=embed)
But then I get the error discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: set_thumbnail() takes 1 positional argument but 2 were given
Could someone tell me what I have done wrong and point me in the right direction?

Problem 1
ctx.guild_icon does not exist, you fix this in your second code by using ctx.guild.icon
Problem 2
discord.Embed.set_thumbnail takes in a named argument for the image.
In fact, it doesn't take in an image at all, but rather a url
Solution
To solve your issue, you should use the following:
embed.set_thumbnail(url=ctx.guild.icon.url)
More info
discord.ext.commands.Context
discord.Embed.set_thumbnail

Related

How to solve bot abandoning previously started game from a different user

I am currently in the process of making a blackjack / gambling bot for me and my friends and the bot works, only the problem(screenshot) is that when user A makes a game and user B makes a Game when user A responds after that user User B has started a game, the original game from user A gets abandoned and takes Users A's response and applies to User
I currently have an active game list which tracks who is in an active game and puts them in/out of one when they complete or start a game but this only solves it when a users is not an in game.
I have edited the code down below to make it less obstructed by a lot of repetitive code
any suggestions on how to fix this code for this problem will be welcome.
from datetime import datetime
import string
import discord
from discord.ext import commands
import random
import sqlite3
class BlackjackCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.game_id = "AAAAAAAA"
self.players_in_game = {}
self.deck = []
self.reset_deck()
self.player_hand = None
self.dealer_hand = None
self.outcome = ""
self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.bet = None
self.conn = sqlite3.connect("credits.db")
self.conn2 = sqlite3.connect("logs.db")
self.cursor = self.conn.cursor()
self.cursor2 =self.conn2.cursor()
def unload(self):
self.conn.close()
self.conn2.close()
def check_hand_value(self, hand)
# game logic to count cards
def reset_deck
# game logic to prevent the deck from going empty
def draw_card
# game logic to append a card to the current player or reset the deck if its empty
#commands.command(name="bj", aliases=["Bj", "blackjack", "BJ" , "Blackjack"])
async def blackjack(self, ctx, bet_amount: int = None):
user_id = ctx.author.id
if bet_amount is None:
embed=discord.Embed(title="Example Higher Lower" , color=0x3498db)
embed.add_field(name="How to Play", value="`You need to get higher amount of card total than the dealer's hand`", inline=False)
embed.add_field(name="Aliases", value="`!hit , !stand`", inline=False)
embed.add_field(name="Win value", value="`x2`", inline=False)
embed.add_field(name="Example command", value="`!bj <credit amount>`", inline=False)
embed.set_footer(text='Do !bj for this message')
await ctx.send(embed=embed)
return
if bet_amount <= 0:
await ctx.send("Invalid bet amount. Please enter a positive number.")
return
self.cursor.execute("SELECT credits FROM credits WHERE user_id=?", (ctx.author.id,))
result = self.cursor.fetchone()
if result is None:
await ctx.send("You do not have any credits use !daily ")
return
self.player_credits = result[0]
if result is None:
await ctx.send("You do not have any credits. Please add some with !daily")
return
if bet_amount > result[0]:
await ctx.send("You do not have enough credits to make that bet.")
return
if ctx.author.id in self.players_in_game:
await ctx.send("You are already in a game. Please finish your current game before starting a new one.")
return
self.bet_amount = bet_amount
self.player_hand = [self.draw_card(), self.draw_card()]
self.dealer_hand = [self.draw_card(), self.draw_card()]
player_total = self.check_hand_value(self.player_hand)
dealer_total = self.check_hand_value([self.dealer_hand[0]])
bet_amount = "{:,}".format(bet_amount)
player_credits = "{:,}".format(self.player_credits)
self.game_id = "BJ" + "".join(random.choices(string.ascii_uppercase + string.digits, k=6))
self.msg = await ctx.send(embed=discord.Embed(title="Blackjack | " + 'User: ' + ctx.author.display_name + " - ID: " + self.game_id, color=0x3498db)
.add_field(name="Your hand", value=' '.join(self.player_hand) + f"\nTotal: **{player_total}**", inline=True)
.add_field(name="Dealers hand", value=' '.join([self.dealer_hand[0]])+ f"\nTotal: **{dealer_total}**", inline=True)
.add_field(name="Bet", value=f"**{bet_amount}** credits", inline=False)
.add_field(name="Credits", value=f"You have **{player_credits}** credits", inline=False)
.add_field(name="Options", value="Use !hit \nUse !stand \nUse !split\n Use !dd", inline=False)
.set_footer(text='Active game')
)
self.players_in_game[user_id] = {}
#commands.command(names="hit", aliases=["h", "Hit" , "H"])
async def hit(self, ctx):
user_id = ctx.author.id
if user_id not in self.players_in_game:
await ctx.send("You don't have an active game to stand in.")
return
game_id = self.players_in_game[user_id]
player_hand = self.player_hand
player_hand.append(self.draw_card())
player_total = self.check_hand_value(player_hand)
dealer_total = self.check_hand_value([self.dealer_hand[0]])
self.player_hand2 = "Empty"
self.player_hand_str = " ".join(self.player_hand)
self.dealer_hand_str = " ".join(self.dealer_hand)
if player_total > 21:
self.outcome = "Lost hit"
self.player_credits -= self.bet_amount
bet_amount = "{:,}".format(self.bet_amount)
player_credits = "{:,}".format(self.player_credits)
self.cursor.execute(f"UPDATE credits SET credits = {self.player_credits} WHERE user_id=?", (ctx.author.id,))
self.conn.commit()
self.cursor2.execute("""INSERT INTO blackjack_logs (game_id, player_hand, player_hand2 ,dealer_hand, player_credits ,bet_amount, outcome, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", (self.game_id, self.player_hand_str, self.player_hand2, self.dealer_hand_str, self.player_credits ,self.bet_amount,self.outcome, self.timestamp,))
self.conn2.commit()
await self.msg.edit(embed=discord.Embed(title="Blackjack | " + 'User: ' + ctx.author.display_name+ " - ID: " + self.game_id , color=0xe74c3c)
.add_field(name="Your hand", value=' '.join(self.player_hand) + f"\nTotal: **{player_total}**", inline=True)
.add_field(name="Dealers hand", value=' '.join([self.dealer_hand[0]])+ f"\nTotal: **{dealer_total}**", inline=True)
.add_field(name="Lost", value=f"**{bet_amount}** credits", inline=False)
.add_field(name="Credits", value=f"You have **{player_credits}** credits", inline=False)
.set_footer(text='Finished game')
)
del self.players_in_game[ctx.author.id]
self.player_hand = None
self.dealer_hand = None
self.bet_amount = None
elif player_total == 21:
self.outcome = "Won hit"
self.player_credits += self.bet_amount
bet_amount = "{:,}".format(self.bet_amount)
player_credits = "{:,}".format(self.player_credits)
self.cursor.execute(f"UPDATE credits SET credits = {self.player_credits} WHERE user_id=?", (ctx.author.id,))
self.conn.commit()
self.cursor2.execute("""INSERT INTO blackjack_logs (game_id, player_hand, player_hand2 ,dealer_hand, player_credits ,bet_amount, outcome, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", (self.game_id, self.player_hand_str, self.player_hand2, self.dealer_hand_str, self.player_credits ,self.bet_amount,self.outcome, self.timestamp,))
self.conn2.commit()
await self.msg.edit(embed=discord.Embed(title="Blackjack | " + 'User: ' + ctx.author.display_name + " - ID: " + self.game_id, color=0x109319)
.add_field(name="Your hand", value=' '.join(self.player_hand) + f"\nTotal: **{player_total}**", inline=True)
.add_field(name="Dealers hand", value=' '.join([self.dealer_hand[0]])+ f"\nTotal: **{dealer_total}**", inline=True)
.add_field(name="Win", value=f"**{bet_amount}** credits", inline=False)
.add_field(name="Credits", value=f"You have **{player_credits}** credits", inline=False)
.set_footer(text='Finished game')
)
del self.players_in_game[ctx.author.id]
self.player_hand = None
self.dealer_hand = None
self.bet_amount = None
else:
bet_amount = "{:,}".format(self.bet_amount)
player_credits = "{:,}".format(self.player_credits)
await self.msg.edit(embed=discord.Embed(title="Blackjack | " + 'User: ' + ctx.author.display_name + " - ID: " + self.game_id, color=0x3498db)
.add_field(name="Your hand", value=' '.join(self.player_hand) + f"\n**Total: **{player_total}", inline=True)
.add_field(name="Dealers hand", value=' '.join([self.dealer_hand[0]])+ f"\n**Total: **{dealer_total}", inline=True)
.add_field(name="Bet", value=f"**{bet_amount}** credits", inline=False)
.add_field(name="Credits", value=f"You have **{player_credits}** credits", inline=False)
.add_field(name="Options", value="Use !hit \n Use !stand\nUse !dd", inline=False)
.set_footer(text='Active game')
)
I also have stand, split and dd command but this amount of code should be enough to give suggestions/edits I believe.
I have tried to edit and add multiple active game lists and assigned an id to to player in the active game list but that also hasn't worked and I tried looking for a basic solution only
So far my conclusion is that I will need to implement a while loop and edit standard bj function and make it all run in 1 command instead of multiple.
The game itself works fine if you are playing solo the problem is really the screenshot.
As far as I can tell, these are all the class variables you have (that are important to a "game"):
game_id
players_in_game
deck
player_hand
dealer_hand
outcome
Now, let's run through some players playing your game. Player A comes along and does blackjack. This initialises all those above variables with values for them. If they were to keep playing by themselves - it would work just fine. However, before Player A can do anything, Player B comes along and runs the blackjack command. This overwrites all the values you had for Player A stored in those variables. If Player A now calls one of your other commands, they'll be using game state from Player B's game.
There's a fundamental flaw in your logic and saving of game state that'll always fail when more than one player tries to play at the same time.
What you need to do, is create some sort of game state object that can be used for that. This can be as simple as a dict, a custom class, DB entry, etc. But it needs to be something.
Using the dict idea:
# when a user uses the `blackjack` command
player_game_state = {"game_id": game_id, "user_id": user_id, "player_hand": player_hand, "dealer_hand": dealer_hand, "bet": bet} # etc, etc, etc
Then, we actually use your self.players_in_game class variable to keep track of all these game states.
# still in the blackjack command - once you setup everything
self.players_in_game[user_id] = game_state
Now, when they call one of the other commands, like hit:
# at the start of the command
player_game_state = self.players_in_game[user_id]
# instead of doing self.player_hand
player_game_state["player_hand"].append(self.draw_card())
Though, maybe your draw_card method, and reset_deck methods need to take the game state as a parameter and modify them. As I'd wager they're currently resetting your class variables as well.
Does that make sense? Hopefully enough that you can try to apply some of it.
TLDR; stop using class variables for storing individual parts of your game state.

How do I create a timestamp in an embed with pycord?

I would like my sent msg log which is an embedded msg to have a timestamp, so it would have a footing like bot_name • Today at 10:48 PM
Here is my current code,
#bot.event
async def on_message(ctx):
if ctx.author.bot: return
else:
log_msg = bot.get_channel(1023451687857442828)
embed = discord.Embed(
title = "Sent Message",
description = f"""This message was sent by{ctx.author.mention}, in {ctx.channel}\n**Message:** "{ctx.content}" """,
color = discord.Colour.green(),
)
embed.set_author(name=ctx.author)
embed.set_footer(text="bot_name")
await log_msg.send(embed=embed)```
You could do the following:
(remaining of your code)
now = datetime.now() # Gets your current time as a datetime object
embed.set_footer(text=f'bot_name • Today at {now.strftime("%H:%M")}') # Set your embed footer with the formatted time
await log_msg.send(embed=embed) # Sends your footer (already present in your original code)
If you don't have it imported already, you'll have to import datetime from datetime, or import datetime and do datetime.datetime.now() instead of just datetime.now()
You can use ctx.message.created_at to add a timestamp. That would look like this in the context of your code:
#bot.event
async def on_message(ctx):
if ctx.author.bot: return
else:
log_msg = bot.get_channel(1023451687857442828)
embed = discord.Embed(
title = "Sent Message",
description = f"""This message was sent by{ctx.author.mention}, in {ctx.channel}\n**Message:** "{ctx.content}" """,
color = discord.Colour.green(),
# message created at code below
timestamp = ctx.message.created_at
)
embed.set_author(name=ctx.author)
embed.set_footer(text="bot_name")
await log_msg.send(embed=embed)
Hope this helps

How do i make my discord.py bot go through a text file and if a user says a word in that file it will delete that message + how to make uptime command

I want my discord.py bot to go through a text file and if a user says a word in that file it will delete that message
elif msg.content == '***':
await msg.channel.send("Dont curse")
await msg.delete()
that is my code but i want to replace *** with a text document
And also another question i have some issues with an uptime command
async def on_ready():
print("Bot is running")
activity = discord.Game(name="!test", type=3)
await client.change_presence(status=discord.Status.idle, activity=activity)
channel = client.get_channel(944665750453497886)
myid = '<#516236429689618467>'
await channel.send("I am online "+myid)
#Uptime code starts
global startdate
startdate = datetime.now()
#client.command()
async def uptime(ctx):
now = datetime.now()
uptime = startdate - now
uptime = uptime.strftime('%d/%h/%M')
await ctx.send(f'Uptime: {uptime}')

Command raised an exception: TypeError: Object of type File is not JSON serializable but no other solution working for me

The Function of discord command named server
#bot.command(name = 'server')
async def _minecraftserverinfo(ctx, ip:str, port:str, servername:str):
if servername == "survival":
svname = "Survival"
elif servername == "lobby":
svname = "Lobby"
#serverembed = createEmbed(ip, port)
#value = f"The server has {status.players.online} players and replied in {status.latency} ms\nThe server replied in {latency} ms\nThe server has the following players online: {','.join(query.players.names)}"
server = MinecraftServer.lookup(ip+':'+port)
#=======================================
#=======================================
# 'status' is supported by all Minecraft servers that are version 1.7 or higher.
status = server.status()
latency = server.ping()
query = server.query()
serverembed = discord.Embed(title = ip, url = "https://www.zer02infinity.com/",description = f"Zero To Infinity Minecraft {svname} Server")#\nThe server has the following players online: {','.join(query.players.names)}")
serverembed.set_thumbnail(url="https://cdn.discordapp.com/attachments/833829693588373534/920017091325747220/2021-12-13_11.png")
serverembed.add_field(name="Players Count", value=f"{status.players.online}/{query.players.max}", inline=True)
serverembed.add_field(name="Direct Connect:", value=f"```mc.zer02infinity.com```", inline=True)
#serverembed.add_field(name="Names:", value=f"{latency} ms", inline=True)
#nl = '\n'
#serverembed.add_field(name="Names:", value=f"{nl}{nl.join(query.players.names)}", inline=False)
#serverembed.add_field(name="Names:", value={'\n'.join(query.players.ping)}, inline=True)
#sending embed
embed = await ctx.send(embed=serverembed)
await embed.add_reaction(emoji)
message_id = embed.id
while True:
server = MinecraftServer.lookup(ip+':'+port)
# 'status' is supported by all Minecraft servers that are version 1.7 or higher.
status = server.status()
latency = server.ping()
query = server.query()
serverembed = discord.Embed(title = ip, url = "https://www.zer02infinity.com/",description = f"Zero To Infinity Minecraft {svname} Server")#\nThe server has the following players online: {','.join(query.players.names)}")
serverembed.set_thumbnail(url="https://cdn.discordapp.com/attachments/833829693588373534/920017091325747220/2021-12-13_11.png")
serverembed.add_field(name="Players Count", value=f"{status.players.online}/{query.players.max}", inline=True)
serverembed.add_field(name="Direct Connect:", value=f"```mc.zer02infinity.com```", inline=True)
#serverembed.add_field(name="Names:", value=f"{latency} ms", inline=True)
#nl = '\n'
problem started after i added a image from local file
file = discord.File("./foo.png", filename="foo.png")
serverembed.add_field(name="Names:", value={','.join(query.players.names)}, inline=False)
serverembed.set_image(url="attachment://foo.png")
#print('Winners are:', *names, sep='\n')
serverembed = await embed.edit(file=file, embed = serverembed)
await asyncio.sleep(60)
pass
So this is the recent code i added where foo.png is maintained by graph.py given below
import discord
from discord.ext import commands
import matplotlib.pyplot as plt
class Equations(commands.Cog):
def __init__(self, bot):
self.bot = bot
def plotlineareq(self, a, b, clr):
x = [0, 10]
y = [(a * i + b) for i in x]
plt.figure(figsize=(10, 10)) # #Size of Graph
plt.xlim(x) # #X Range [-6,6]
plt.ylim(x) # #Y Range [-6,6]
axis = plt.gca() # #Get Current Axis
plt.plot(axis.get_xlim(), [0, 0], 'k--') # #X Axis Plots Line Across
plt.plot([0, 0], axis.get_ylim(), 'k--') # #Y Axis Plots Line Across
plt.locator_params(axis="x", nbins=20)
plt.locator_params(axis="y", nbins=20)
plt.plot(x, y, label='linear', linestyle='solid', color=clr)
plt.ylabel('Players')
plt.xlabel('Time')
mm = str(a)
bb = str(b)
plt.title('Live Status')
#plt.grid()
plt.savefig("foo.png")
#commands.command()
async def linear(self, ctx, equation):
try:
equation = equation.replace(" ", "")
mx = equation.split("x")[0]
mx = equation.replace("x", "").replace("y=", "")
bx = equation.split("+")[1]
self.plotlineareq(mx, bx, 'b')
file = discord.File("foo.png", filename='foo.png')
embed = discord.Embed(color=0xff0000)
embed = embed.set_image(url="attachment://foo.png")
await ctx.send(file=file, embed=embed)
except Exception as e:
await ctx.send(f"An error occured: {e}")
def setup(bot):
bot.add_cog(Equations(bot))
After executing it gives the following error in error log-
Command raised an exception: TypeError: Object of type File is not JSON serializable

Discord.py True Key Permissions

#commands.command()
#commands.cooldown(1, 3, commands.BucketType.user)
async def roleinfo(self,ctx,*,role:discord.Role):
guild = ctx.guild
perms = ", ".join(str(permission) for permission in role.permissions if true_false == 'true')
embed = discord.Embed(description=f'''
>〉 **Role Created On:** {role.created_at.strftime("%d/%m/%Y")}
>〉 **Roles ID:** {role.id}
>〉 **Roles Color:** {role.color}
>〉 **Mentionable:** {role.mentionable}
>〉 **Position:** {role.position}
>〉 **Hoist:** {role.hoist}
>〉 **Permissions:** {perms}
''', color=discord.Color.orange(),timestamp=ctx.message.created_at)
embed.set_author(name=f"{role.name}s Information", icon_url=guild.icon_url)
embed.set_footer(text=f"Requested by {ctx.author}.", icon_url=ctx.author.avatar_url)
await ctx.reply(embed=embed, mention_author=False)
I am trying to make a roleinfo command that filters out the true Key Permissions of a role, but the response seems to be empty. I am having no errors.
This is happening because Role.permissions returns a Permissions object, rather than a List[Permission] object. You can get each permission’s value by iterating through the role’s permissions.
for permission in iter(role.permissions):
print(permission)
The following code will print tuples containing the info for each permission.
(str(permission), bool(value))
This can be applied to your code as so:
perms = ", ".join(list(filter(lambda x: x[0] if x[1] else "", iter(role.permissions))))

Resources