Hi I had this niggling issue with a cog (bot module) on writing and I keep getting an UnboundLocalError: Referenced before assignment I'm aware this is a very common issue however I'm not seeing the issue.
The module works but every time a post is reacted to with a star it throws off this error in the console.
The error is:
starboard.py", line 22, in on_reaction_add
if emoji_count > 0: #if 0 then 1 counts
UnboundLocalError: local variable 'emoji_count' referenced before assignment
The area of more specific I'm looking at is:
async def on_reaction_add(self, reaction, user):
for guild in self.bot.guilds:
chan = get(guild.channels, name="starboard")
if chan:
if reaction.message.author == user:
return
if reaction.emoji == '⭐' or reaction.emoji == '🌟':
if not chan:
return
emoji_count = reaction.message.reactions[0].count
msg = f"{reaction.message.author.mention} your post was posted to starboard."
em = discord.Embed(color=discord.Color(random.randint(0x000000, 0xFFFFFF)))
display = f"""{reaction.message.content}"""
em.description = display
em.set_author(name=reaction.message.author.name, icon_url=reaction.message.author.avatar_url)
em.set_footer(text=f"Posted in: #{chan.name}")
em.timestamp = dt.datetime.utcnow()
try:
img_url = reaction.message.attachments[0].url
except IndexError:
img_url = None
if not img_url:
try:
img_url = reaction.message.embeds[0].url
except IndexError:
img_url = None
if img_url:
em.set_image(url=str(img_url))
if emoji_count > 0: #if 0 then 1 counts
if not chan:
return
await chan.send(msg)
await chan.send(embed=em)
If anyone can tell me whats going on here and where I'm going wrong I'd much appreciated it.
When your if statement condition in if reaction.emoji == '⭐' or reaction.emoji == '🌟': doesn't return True , emoji_count won't get initialized
(emoji_count = reaction.message.reactions[0].count)
So when you try to use it a couple of lines underneath in if emoji_count > 0: it causes
local variable 'emoji_count' referenced before assignment, which is exactly what it says, python not being able to find your variable's initialization anywhere in the code that ran
I think what is being said here is the following:
if emoji_count >= 2 :
if not chan:
return True
As said in the previous answers it should be
if reaction.emoji == '⭐' or reaction.emoji == '🌟' is True:
Related
I am trying to scrape reference texts from this: paper
When I go to the site, the references section does not show up. To see them, I should either click "References" or "+Show References". I am trying to find references link and click it.
Here is my code:
browser.get('https://doi.org/10.3847/1538-4357/abb3c9')
refCheck = ["references", "cited literature", "literature cited", "refs"]
for h in range(0, len(browser.find_elements(By.XPATH, '//a[#href]'))):
textSearch = browser.find_elements(By.XPATH, '//a[#href]')[h].text
href = browser.find_elements(By.XPATH, '//a[#href]')[h].get_attribute("href")
if (textSearch.lower() in refCheck) & (len(href) > 0):
browser.find_elements(By.XPATH, '//a[#href]')[h].get_attribute("href")
print(h)
print(textSearch)
print(href)
break
browser.get(href)
attrList = []
refCheck = ["references", "cited literature", "literature cited", "refs"]
tags = ["ol","ul"]
for t in tags:
if len(browser.find_elements(By.TAG_NAME, t)) > 0:
for i in range(0, len(browser.find_elements(By.TAG_NAME, t))):
for attr in browser.find_elements(By.TAG_NAME, t)[i].get_property('attributes'):
for rc in refCheck:
if (rc in attr['name'].lower()) | (rc in attr['value'].lower()):
attrList.append(t)
attrList.append(i)
attrList.append(attr['name'])
attrList.append(attr['value'])
print(attr['name'])
print(attr['value'])
print(len(browser.find_elements(By.TAG_NAME, t)[i].find_elements(By.XPATH,'./li')))
if len(attrList) > 0:
break
if len(attrList) > 0:
break
if len(attrList) > 0:
break
cnt = 0
for f in browser.find_elements(By.TAG_NAME, t)[i].find_elements(By.XPATH, './li'):
print(f.text)
if len(f.text) > 0:
refList.append(f.text)
cnt += 1
print(cnt)
However, the returned text is always empty.
PS. By the way, I have tried to click href I reached instead of browser.get(href), however it does not work as well. When I tried to get the hyperlink through get_attributes("href"), it always returned a string so could not click.
How should I get that text?
EDIT:
Found the answer here: link
Using get_attribute("textContent") solved my issue.
You can use alternatively crossref.org API if you search by DOI it will give you a JSON response that contains 'reference'. You can play with the json however you want.
import requests
def get_ref(doi):
url = f'https://api.crossref.org/works/{doi}'
response = requests.get(url)
if response.status_code == 200:
response = response.json()
return response['message']['reference']
return None
doi = 'doi.org/10.3847/1538-4357/abb3c9'
get_ref_count(doi)
I am using the following function to implement a program that changes its behavior depending on the IP of the connected PC.
There is a problem with this function that if something tries to login and fails, it may get the IP of the failed one.
And now that we've encountered that possibility, the program is broken.
What edits do I need to make to make this function behave as expected?
import psutil
def get_ip(port=3389):
ip = ""
for x in psutil.net_connections():
if x.status == "ESTABLISHED" and x.laddr.port == port:
ip = x.raddr.ip
break
I changed the function based on Bijay Regmi's comment. Thank you. wmi was difficult for me, so I used win32evtlog to read it out little by little. I am working on improving readability and finding bugs little by little.
def systime(xml):
return datetime.fromisoformat(xml.find(f'{ns}System/{ns}TimeCreated').get('SystemTime')[:-2] + "+00:00")
def last_event(handle,
event_id,
condition: Callable[['Event'], bool] = None) -> Optional['Event']:
now = datetime.now(tz=timezone.utc)
while True:
events = win32evtlog.EvtNext(handle, 20)
if not events:
break
for event in events:
xml_content = win32evtlog.EvtRender(event, win32evtlog.EvtRenderEventXml)
obj = Event(ET.fromstring(xml_content))
if obj.EventID == event_id:
if obj.SystemTime + timedelta(minutes=5) < now:
return None
if condition and not condition(obj):
continue
return obj
class Event:
def __init__(self, xml: ET.Element):
self.EventID = xml and xml.find(f'{ns}System/{ns}EventID').text
self.SystemTime = xml and systime(xml)
self.xml = xml
if self.EventID == '24':
self.IpAddress = xml.find(f'{ns}UserData/{{Event_NS}}EventXML/{{Event_NS}}Address').text
elif self.EventID == '4624':
self.IpAddress = xml.find(f'{ns}EventData/{ns}Data[#Name="IpAddress"]').text
else:
self.IpAddress = None
Function PoNanswer should return True or False, it is a loop which can be stoped only when you say Yes,... or No,... and when you say it, it should return. But very strangely it is not returning... How to fix it? thank you in advance)
def PoNanswer(voice_data):
for i in pANSWER_LIST:
if i in voice_data.split():
print('true')
return True
for i in nANSWER_LIST:
if i in voice_data.split():
print('false')
return False
voice_data = record_audio('I did not get it. Please repeat')
PoNanswer(voice_data)
class Command:
def __init__(self, raw_command):
self.raw_command = raw_command
self.key_word = False
self.action_word = False
self.processing()
def processing(self):
print(self.raw_command)
for i in self.raw_command.split():
if i in COMMANDS_LIST:
self.key_word = i
elif i in ACTION_WORD_LIST:
self.action_word = i
if self.key_word == COMMANDS_LIST[0]:
if self.action_word:
speak('ordering...')
main('-//-')
else:
if PoNanswer(record_audio(ADDITIONAL_QUESTIONS[0])):
self.raw_command = self.raw_command + "order"
print("mod")
self.processing()
else:
speak('Okay')
main('-//-')
self.processing()
In this case, I should have used a loop ( while 1: ) instead of calling the same function inside the function.
def PoNanswer(voice_data):
while 1:
for i in pANSWER_LIST:
if i in voice_data.split():
return True
for i in nANSWER_LIST:
if i in voice_data.split():
return False
voice_data = record_audio('I did not get it. Please repeat')
This ^ is fortunately working.
def func(var):
...
func(var)
This ^ wasn't, I have no clue why, but I am happy it is working now))
I'm trying to make a multiple-choice trivia background task. I'm trying to await client.wait_for_message only for either the correct answer or the incorrect choices. I'm checking message.content but I'm missing something because no matter what anyone types, it says "incorrect answer" UNLESS it's the correct answer. If someone types something other than the incorrect answer or correct answer then I want it to ignore their text.
async def trivia_loop():
await client.wait_until_ready()
channel = client.get_channel("123456778999533")
triviamonies = random.randint(1250, 2550)
while not client.is_closed:
await client.send_message(channel, '**Category**: {}\n**Difficulty**: {}\n\n{}\n\n**Potential Answers:**\n{}'.format(category, formatdiff, formatquestion, '\n'.join(tup)))
winner = ''
def check(m):
return m.content.lower() == formatanswer.lower() and m.content.lower() != incorrectanswer1 or incorrectanswer2 or incorrectanswer3
while winner == '':
answerid = await client.wait_for_message(timeout=420, channel=channel, check=check)
if answerid is None:
winner = 1
await client.delete_message(questionsend)
await client.send_message(channel, 'No one answered correctly! The answer was {}'.format(formatanswer))
await asyncio.sleep(840)
elif get_triviaguessesTaken(answerid.author) < 1 and answerid.content.lower() == formatanswer.lower():
winner = 1
await client.delete_message(questionsend)
await client.send_message(channel, '**{}** is correct!\n{} earns **${:,}** !'.format(formatanswer, answerid.author.mention, triviamonies))
add_dollars(answerid.author, triviamonies)
add_trivias(answerid.author, 1)
await asyncio.sleep(900)
elif get_triviaguessesTaken(answerid.author) < 1 and answerid.content.lower() == incorrectanswer1 or incorrectanswer2 or incorrectanswer3:
await client.send_message(channel, '**{}** that is incorrect! Please try again on the next trivia question'.format(answerid.author.mention))
add_triviaguessesTaken(answerid.author, 1)
elif get_triviaguessesTaken(answerid.author) > 0 and answerid.content.lower() == incorrectanswer1 or incorrectanswer2 or incorrectanswer3:
await client.send_message(channel, '{} you have already tried to guess this trivia question. Try again on the next one!'.format(answerid.author.mention))
Discord.py Version:
From the looks of your code, you're still using the async version of d.py (v0.16.12), and you haven't moved to the more up-to-date and stable rewrite version of d.py.
I can highly recommend running pip install --upgrade discord.py for the most recent stable version. Make sure you do this and rewrite your code sooner rather than later, as it'll be less of a pain when you have less code to work with.
Wait_for() usage in rewrite:
The docs use an example in an on_message event, but I'll make an example here to suit your case with a command instead, so you have both ways available to you and can mix-and-match:
#bot.command(aliases=["trivia"])
async def starttrivia(ctx):
answers = ["paris", "london", "oslo"]
await ctx.send(f"What's the capital of France?\n\n*Potential answers:*\n{', '.join(answers)}")
correct = False
def check(m):
for a in answers:
if a in m.content.lower():
return True
while not correct:
try:
reply = await bot.wait_for("message", check=check, timeout=30)
if "paris" in reply.content.lower():
await ctx.send(f"Correct! {reply.author.mention} got the right answer!")
correct = True
else:
await ctx.send("Incorrect, try again!")
except asyncio.TimeoutError: # exception thrown when no reply is sent in time
await ctx.send("Nobody guessed for 30 seconds! The answer was: Paris")
break
I am writing tests for an API with pytest.
The tests are structured like that:
KEEP_BOX_IDS = ["123abc"]
#pytest.fixture(scope="module")
def s():
UID = os.environ.get("MYAPI_UID")
if UID is None:
raise KeyError("UID not set in environment variable")
PWD = os.environ.get("MYAPI_PWD")
if PWD is None:
raise KeyError("PWD not set in environment variable")
return myapi.Session(UID, PWD)
#pytest.mark.parametrize("name,description,count", [
("Normal Box", "Normal Box Description", 1),
("ÄäÖöÜüß!§", "ÄäÖöÜüß!§", 2),
("___--_?'*#", "\n\n1738\n\n", 3),
])
def test_create_boxes(s, name, description, count):
box_info_create = s.create_box(name, description)
assert box_info_create["name"] == name
assert box_info_create["desc"] == description
box_info = s.get_box_info(box_info_create["id"])
assert box_info["name"] == name
assert box_info["desc"] == description
assert len(s.get_box_list()) == count + len(KEEP_BOX_IDS)
def test_update_boxes(s):
bl = s.get_box_list()
for b in bl:
b_id = b['id']
if b_id not in KEEP_BOX_IDS:
new_name = b["name"] + "_updated"
new_desc = b["desc"] + "_updated"
s.update_box(b_id, new_name, new_desc)
box_info = s.get_box_info(b_id)
assert box_info["name"] == new_name
assert get_box_info["desc"] == new_desc
I use a fixture to set up the session (this will keep me connected to the API).
As you can see I am creating 3 boxes at the beginning.
All test that are following do some sort of operations on this 3 boxes. (Boxes are just spaces for folders and files)
For example: update_boxes, create_folders, rename_folders, upload_files, change_file names, etc..
I know it's not good, since all the tests are dependent from each other, but if I execute them in the right order the test is valid and thats enough.
The second issue, which borders me the most, is that all the following tests start with the same lines:
bl = s.get_box_list()
for b in bl:
b_id = b['id']
if b_id not in KEEP_BOX_IDS:
box_info = s.get_box_info(b_id)
I always need to call this for loop to get each boxs id and info.
I've tried to put it in a second fixture, but the problem is that then there will be two fixtures.
Is there a better way of doing this?
Thanks