Why is it bringing the Userid back and not the text_max? - python

Hi so im having a problem where when I try to use this command its bringing the USERID instead of what im trying to get heres the error
File "goonie.py", line 421, in spam
spammers = users[str(ctx.author.id)]['text_max']
KeyError: '932428536176848938'
The numbers are the "ctx.author.id" and im trying to get the "text_max"
async def spam(ctx, message,amount):
users = await get_paid_data()
spammers = users[str(ctx.author.id)]['text_max']
if amount > spammers:
if str(ctx.author.id) in users:
if users[str(ctx.author.id)]['vip'] == 'Y':
timeleft = datetime.strptime(users[str(ctx.author.id)]['expDate'],'%Y-%m-%d') - datetime.now()
if timeleft.days <= 0:
em = discord.Embed(color=0x000000, description="Sorry your plan on this tool has expired")
await ctx.send(embed=em) ```

users is a dictionary.
You first access the str(ctx.author.id) key in the dictionary.
The error is telling you the dictionary does not contain a key corresponding to the value of string value of ctx.author.id. Therefore, you cannot access text_max because the first part of your dict navigation is incorrect.
You should print users and see what it contains:
print(users)
My initial guess is that you're converting the id to a string when it in-fact doesn't need to be converted, but it's impossible to say without seeing the contents of the dictionary.

Related

KeyError with Riot API Matchv5 When Trying To Pull Data

I'm trying to pull a list of team and player stats from match IDs. Everything looks fine to me but when I run my "for loops" to call the functions for pulling the stats I want, it just prints the error from my try/except block. I'm still pretty new to python and this is my first project so I've tried everything I can think of in the past few days but no luck. I believe the problem is with my actual pull request but I'm not sure as I'm also using a GitHub library I found to help me with the Riot API while I change and update it to get the info I want.
def get_match_json(matchid):
url_pull_match = "https://{}.api.riotgames.com/lol/match/v5/matches/{}/timeline?api_key={}".format(region, matchid, api_key)
match_data_all = requests.get(url_pull_match).json()
# Check to make sure match is long enough
try:
length_match = match_data_all['frames'][15]
return match_data_all
except IndexError:
return ['Match is too short. Skipping.']
And then this is a shortened version of the stat function:
def get_player_stats(match_data, player):
# Get player information at the fifteenth minute of the game.
player_query = match_data['frames'][15]['participantFrames'][player]
player_team = player_query['teamId']
player_total_gold = player_query['totalGold']
player_level = player_query['level']
And there are some other functions in the code as well but I'm not sure they are faulty as well or if they are needed to figure out the error. But here is the "for loop" to call the request and defines the variable 'matchid'
for matchid_batch in all_batches:
match_data = []
for match_id in matchid_batch:
time.sleep(1.5)
if match_id == 'MatchId':
pass
else:
try:
match_entry = get_match_row(match_id)
if match_entry[0] == 'Match is too short. Skipping.':
print('Match', match_id, "is too short.")
else:
match_entry = get_match_row(match_id).reshape(1, -1)
match_data.append(np.array(match_entry))
except KeyError:
print('KeyError.')
match_data = np.array(match_data)
match_data.shape = -1, 17
df = pd.DataFrame(match_data, columns=column_titles)
df.to_csv('Match_data_Diamond.csv', mode='a')
print('Done Batch!')
Since this is my first project any help would be appreciated since I can't find any info on this particular subject so I really don't know where to look to learn why it's not working on my own.
I guess your issue was that the 'frame' array is subordinate to the array 'info'.
def get_match_json(matchid):
url_pull_match = "https://{}.api.riotgames.com/lol/match/v5/matches/{}/timeline?api_key={}".format(region, matchid, api_key)
match_data_all = requests.get(url_pull_match).json()
try:
length_match = match_data_all['info']['frames'][15]
return match_data_all
except IndexError:
return ['Match is too short. Skipping.']
def get_player_stats(match_data, player): # player has to be an int (1-10)
# Get player information at the fifteenth minute of the game.
player_query = match_data['info']['frames'][15]['participantFrames'][str(player)]
#player_team = player_query['teamId'] - It is not possibly with the endpoint to get the teamId
player_total_gold = player_query['totalGold']
player_level = player_query['level']
return player_query
This example worked for me. Unfortunately it is not possible to gain the teamId only through your API-endpoint. Usually the players 1-5 are in team 100 (blue side) and 6-10 in team 200 (red side).

IMAP COPY command not working on Inbox - Python

Iam using Python3.6 with IMAP4 module.Iam trying to copy emails from "Inbox" to "mytestfolder".
Iam getting "OK" as the response but the email itself is not being copied to "mytestfolder".
Where as the same code snippet is working for "someotherfolder" to "mytestfolder" without any problem for the first time and after that it doesn't work. Below is the code snippet can someone please help me resolve this.
import config
import imaplib
from creds import username,password
imap = imaplib.IMAP4_SSL(config.imap_server,config.imap_port)
r, d = imap.login(username, password)
assert r == 'OK', 'login failed: %s' % str (r)
print(" > Signed in as %s" % username, d)
imap.select("Inbox")
r, d = imap.search(None, "ALL")
allIds = d[0].decode('utf8').split(' ')
''' Login works and iam getting msg_ids as well'''
for msg_id in allIds:
apply_lbl_msg = imap.uid('COPY', msg_id, 'mytestfolder')
if apply_lbl_msg[0] == 'OK':
mov, data = imap.uid('STORE', msg_id , '+FLAGS', '(\Deleted)')
imap.expunge()
TLDR: You're miscounting by removing things and then indexing by what used to be the order.
Your code does:
r, d = imap.search(None, "ALL")
"Give me the sequence numbers of all messages in the inbox", so you get 1, 2, 3, 4, 5 and so on. The last number in d will equal the return value from select() a few lines above. Then you loop, I'll explain the first iteration:
apply_lbl_msg = imap.uid('COPY', msg_id, 'mytestfolder')
if apply_lbl_msg[0] == 'OK':
"Copy the first message to mytestfolder, and if that works…."
mov, data = imap.uid('STORE', msg_id , '+FLAGS', '(\Deleted)')
imap.expunge()
"… then delete the first message in the inbox", which means that what was the second message now becomes the first.
The next iteration operates on the message that's currently the second in the mailbox, and was once the third, so you never operate on the message that was 2 at the start. The third iteration operates on the message that's currently the third, and was once the... fifth I think? It doesn't matter.
You can make this correct by switching to the UID versions of the same. UIDs don't change as you renumber.
You could also make this correct and very much faster by issuing one single COPY command that copies all messages, and then one single STORE that marks them as deleted. You don't even need the SEARCH, because the result of the search is just all the numbers from 1 to the return value of select().

Compare 2 JSON files in python and check if item is changed

Maybe the title is a bit confusing but my brain is stuck on this for like days now. So here is my "problem". I am redoing my Discord Bot and I have a small task that will check 2 JSON files (same format, different data) and there is a difference between them it will send a message.
This code needs to load 2 JSON files ("VATSIM_DATA_old.json & VATSIM_Data_new.json") and compare them and find differences. Now for simplicity, I reduced code so I just get if someone came online and if they are no longer online.
So my flow for this is something like this:
-When bots start, fetch JSON data and save it to file so we can compare updated data with this file,
-Now it is time to check if someone came online by fetching new data from the same link and saving it to the new file,
-Load both files as JSON so we can find all items inside of them and compare if some items are present in both or only in one of them,
-After comparing them and doing actions such as sending messages to the channel let's save that new data to our Old_Data.json file and go to sleep for X min (I set it to 5),
The problem I have is that it will send the same message every time a task is started. So my logic here was ok let's check if files are changing and they are but the code still somehow ignores part of the code that tells him if data is not changed here simply pass.
So here is my code:
atc = ["ADR_CTR", "ADR_W_CTR", "ADR_U_CTR", "ADR_E_CTR"] #this is short version of array which needs to be checked. This will most likely be moved to the config file so code is cleaner
#tasks.loop(minutes=5)
async def atcAnnoucements(self):
#Load old and new VATSIM Data for comparing!
with open("VATSIM_Data_old.json", encoding="utf-8") as f:
data = json.load(f)
file = open("VATSIM_Data_new.json", "w", encoding="utf-8")
file.write(requests.get('https://data.vatsim.net/vatsim-data.json').text)
file.close()
with open("VATSIM_Data_new.json", encoding="utf-8") as s:
data1 = json.load(s)
#Check if new VATSIM data contains some changes in online atc
#If callsign from atc array is present in VATSIM_Data_old it will check is same controller active or not
#If the controller is not changed it will skip, if new controller comes online it will send a message that the ATC station came online
for item in data1['clients']:
if item['callsign'] in data['clients']:
pass
else:
if item['callsign'] in atc:
time_start = item['time_logon']
time_logg = time_start[:19]
logon_start = datetime.strptime(time_logg, '%Y-%m-%dT%H:%M:%S')
time_logon = logon_start.strftime('%H:%M')
channel = self.bot.get_channel(781834455765483562)
embed = Embed(title="ATC Annoucement", description="`New controller just logged in!`", color=0x00ff4c)
embed.add_field(name='Position', value=f"`{item['callsign']}`", inline=False)
embed.add_field(name='Frequency', value=f"`{item['frequency']}`", inline=False)
embed.add_field(name='Controller', value=f"`{item['realname']}`", inline=False)
embed.set_footer(text=f"Logged on at: {time_logon}")
await channel.send(embed=embed)
if item['callsign'] in data['clients'] and atc and not data1['clients']:
channel = self.bot.get_channel(781834455765483562)
embed2 = Embed(title="ATC Logged off!", description=f"{item['callsign']} just logged off!", color=0xff8800)
await channel.send(embed=embed2)
file = open("VATSIM_Data_old.json", "w", encoding="utf-8")
file.write(requests.get('https://data.vatsim.net/vatsim-data.json').text)
file.close()
print("Saved new VATSIM Data!")
EDIT:
In my first attempt to just get 1 message, I did something like the code below and it worked. But as soon as I changed to the code above it simply sends the same message all over again
json1 = open("VATSIM_Data_old.json", "r", encoding="utf-8").read()
xy = json.dumps(json1)
s1 = json.loads(xy)
t = requests.get('https://data.vatsim.net/vatsim-data.json').json()
xx = json.dumps(t)
s = json.loads(xx)
for item in s['clients']:
if item['callsign'] in atc:
if item['callsign'] in s1:
pass
else:
if item['callsign'] in atc:
time_start = item['time_logon']
time_logg = time_start[:19]
logon_start = datetime.strptime(time_logg, '%Y-%m-%dT%H:%M:%S')
time_logon = logon_start.strftime('%H:%M')
channel = self.bot.get_channel(781834455765483562)
embed = Embed(title="ATC Annoucement", description="`New controller just logged in!`", color=0x00ff4c)
embed.add_field(name='Position', value=f"`{item['callsign']}`", inline=False)
embed.add_field(name='Frequency', value=f"`{item['frequency']}`", inline=False)
embed.add_field(name='Controller', value=f"`{item['realname']}`", inline=False)
embed.set_footer(text=f"Logged on at: {time_logon}")
await channel.send(embed=embed)```

Issue with if and else statement in a loop

Hi I'm having an issue checking through a list codes that are stored in a temp dictionary and matching ones that exist and if one doesn't exist then print/await a different result. I'm doing this by comparing the uses for each invite before the user joined and after they joined.
It seems as if the if statement if invite.uses < find_invite_by_code(invites_after_join, invite.code).uses: is being ignored and the else statement is being printed/awaited instead for both expired and none expired code. I'm not too sure why this is happening. Help would be appreciated.
I have commented parts of the code for a better understanding.
Here is my code:
invites = {} #temporary dict to store the codes
# A function to find an invite in a guilds.invites() list
def find_invite_by_code(invite_list, code):
# Simply looping through each invite in an
# invite list which we will get using guild.invites()
for inv in invite_list:
# Check if the invite code in this element
# of the list is the one we're looking for
if inv.code == code:
# If it is, we return it.
return inv
#commands.Cog.listener()
async def on_member_join(self, member):
time = datetime.utcnow()
users = len([e.name for e in member.guild.members])
name = member
name = " ~ ".join((name.name, name.nick)) if name.nick else name.name
# Getting the invites before the user joining
# from our cache for this specific guild
invites_before_join = invites[member.guild.id]
# Getting the invites after the user joining
# so we can compare it with the first one, and
# see which invite uses number increased
invites_after_join = await member.guild.invites()
# Loops for each invite we have for the guild
# the user joined.
for invite in invites_before_join:
# Now, we're using the function we created just
# before to check which invite count is bigger
# than it was before the user joined.
if invite.uses < find_invite_by_code(invites_after_join, invite.code).uses:
# Now that we found which link was used we'll start the embed
joinmsg = discord.Embed(title=f'{member.name}#{member.discriminator} has joined', timestamp=time, colour=discord.Color(random.randint(0x000000, 0xFFFFFF)))
joinmsg.add_field(name="**Account Created:**", value=member.created_at.strftime("%#d %b %Y, at %I:%M%p"), inline=True)
joinmsg.add_field(name="**Invite:**", value=f"||{invite.code}||", inline=True)
joinmsg.add_field(name="**Inviter:**", value=f"{invite.inviter}", inline=False)
joinmsg.set_footer(text=f"Member {users} • User ID: {member.id}")
joinmsg.set_thumbnail(url=member.avatar_url)
await self.bot.send_log_message(member.guild, embed=joinmsg)
#We use an else statement if a NoneType is returned this would happen if the invite link has expired.
else:
# Create the embed to be sent
joinmsg = discord.Embed(title=f'{member.name}#{member.discriminator} has joined', timestamp=time, colour=discord.Color(random.randint(0x000000, 0xFFFFFF)))
joinmsg.add_field(name="**Account Created:**", value=member.created_at.strftime("%#d %b %Y, at %I:%M%p"), inline=True)
joinmsg.add_field(name="**Invite:**", value=f"Expired", inline=True)
joinmsg.set_footer(text=f"Member {users} • User ID: {member.id}")
joinmsg.set_thumbnail(url=member.avatar_url)
await self.bot.send_log_message(member.guild, embed=joinmsg)
# We will now update our cache so it's ready
# for the next user that joins the guild
invites[member.guild.id] = invites_after_join
# return to prevent looping when we already got what we want
return
It looks like something isn't happening quite the way you want it to, I would add a print function before it and print the values of invite.uses and find_invite_by_code(invites_after_join, invite.code).uses and then print the type of them too, if you still can't spot the error, then we'll have a problem
print(invite.uses, find_invite_by_code(invites_after_join, invite.code).uses)
print(type(invite.uses), type(find_invite_by_code(invites_after_join, invite.code).uses))

How to properly format requests API json response with python?

I am working on a discord bot that gets information from an API. For this command I want to return some information, and display it nicely for the user. This is the code (Python 3.8.3, discord.py):
import json
import requests
import discord
#bot.command(name="clan")
async def clan_command(ctx, clan_id:int):
response = requests.get(f'https://api.worldoftanks.eu/wot/clans/info/?application_id=0a833f3e275be2c9b458c61d6cedf644&clan_id={clan_id}&fields=leader_name%2C+members_count%2C+tag%2C+motto%2C+name%2C+emblems.x256%2C+color', params={'q': 'requests+language:python'})
json_response = response.json()
repository = json_response["data"]
clan_name =
clan_colour =
clan_url = f"https://eu.wargaming.net/clans/wot/{clan_id}/"
clan_logo =
clan_commander =
clan_member_count =
clan_tag =
clan_motto =
embed = discord.Embed(title=clan_name (clan_tag), colour=clan_colour, url=clan_url)
embed.set_thumbnail(url=clan_logo)
embed.add_field(name="Commander:", value=clan_commander, inline=True)
embed.add_field(name="Member count:", value=clan_member_count, inline=True)
embed.add_field(name="Clan motto:", value=clan_motto, inline=True)
await ctx.channel.send(embed=embed)
Screenshot of the API response with input if I write it to a file *clan 500075680: https://imgur.com/a/BzkctRP
When I run this code:
for key, value in repository.items():
print(f"key {key} has value {value}")
I get this in console:
key 500075680 has value {'members_count': 81, 'name': 'Reloading', 'color': '#B80909', 'leader_name': 'Joc666', 'emblems': {'x256': {'wowp': 'https://eu.wargaming.net/clans/media/clans/emblems/cl_680/500075680/emblem_256x256.png'}}, 'tag': '-RLD-', 'motto': "In the end, we only regret the chances we didn't take."}
So the key clan_id (which is a input argument that changes) has multiple values.
My question is, if I take the clan_id = 500075680 for example, how do I display from value 'name': 'Reloading', Reloading individually?
How can I define the variables in my code?
Fixed it thanks to you guys:
I had the clan_id argument specified as an integer, removing that makes it work:
clan_name = repository[clan_id]['name']
Assuming value is dictionary
to acess the value of name from value dictionary use value['name']
for key, value in repository.items():
print(f"key {key} has value {value['name']}")
from the image you shared, you can get the value of name by using this repository['data'][key]['name']
if there are list of responses
example:
repository=[{key1:{'name':name1}},{key2:{'name':name2}}
for item in repository:
key=next(iter(item))
print(item[key]['name'])
repository is a list holding all responses
Try using json.loads().
For example to get the value of name you could parse your json into a python dict and retrieve it from there.
for key, value in repository.items():
value_dict = json.loads(value)
print(value_dict["name"])
Here is another nice way to do it.
json_object = json.loads(json_response)
formatted_data = json.dumps(json_object, indent=2)
print(formatted_data)
json.dumps method with indent will formate it and you can controle the formatting with indent value.
It is equivalent to PHP array formatting after converting JSON to an array.
echo "<pre>";
print_r()

Categories