0

I'm receiving an error in my code that my variable (jokes) is being referenced before assignment. For reference, here is my code (all of it) :

import discord
import os
import requests
import json
import random
from replit import db
from keep_alive import keep_alive

client = discord.Client()


sad_words = ["sad", "Sad" "depressed", "unhappy", "angry", "miserable", "depressing", "rip", "Rip", "annoyed", "suicide", "bash", "beat", "cut", "kill", "murder", "murdering", "killing"]

happy_words = ["better", "happy", "Happy" "thanks", "Thanks", "Thanks!", "thanks!", "amazing", "overjoyed", "grateful", "joyous", "helped", "great"]

jokes = ["I could use a joke right now", "I want to laugh", "I want to see something funny", "I could use a joke"]

starter_encouragements = [
  "Cheer up!",
  "Hang in there.",
  "You are a great person!"
]

if "responding" not in db.keys():
  db["responding"] = True

responses = [
  "You're welcome!", 
  "I'm glad I could help.", 
  "Have a great rest of your day.", 
  "Don't hesitate to ask for my help in the future!",
  "Oh, and in case I don't see you, good afternoon,  good evening, and good night!", 
]

def get_quote():
  response = requests.get("https://zenquotes.io/api/random")
  json_data = json.loads(response.text)
  quote = json_data[0]['q'] + " -" + json_data[0]['a']
  return(quote)


def update_encouragements(encouraging_message):
  if "encouragements" in db.keys():
    encouragements = db["encouragements"]
    encouragements.append(encouraging_message)
    db["encouragements"] = encouragements
  else:
    db["encouragements"] = [encouraging_message]

def update_jokes(comedy):
  if "jokes" in db.keys():
    jokes = db["jokes"]
    jokes.append(comedy)
    db["jokes"] = jokes
  else:
    db["jokes"] = [comedy]

def delete_encouragment(index):
  encouragements = db["encouragements"]
  if len(encouragements) > index:
    del encouragements[index]
    db["encouragements"] = encouragements

def delete_jokes(index):
    jokes = db["jokes"]
    if len(jokes) > index:
      del jokes[index]
      db["jokes"] = jokes


@client.event
async def on_ready():
  print('We have logged in as {0.user}'.format(client))

@client.event
async def on_message(message):
  if message.author == client.user:
    return

  msg = message.content

  if msg.startswith('+inspire'):
    quote = get_quote()
    await message.channel.send(quote)
  
  if msg.startswith('+add'):
    comedy = msg.split("+add mm ",1)[1]
    update_encouragements(starter_encouragements)
    await message.channel.send("New encouraging message added :D")

  if msg.startswith('+add joke'):
    comedy = msg.split("+add joke ",1)[1]
    update_jokes(comedy)
    await message.channel.send("New joke added ;D")


  if db["responding"]:
    options = starter_encouragements
    if "encouragements" in db.keys():
      options = options + db["encouragements"].value

    if any(word in msg for word in sad_words):
      await message.channel.send(random.choice(options))

    if any(word in msg for word in happy_words):
      await message.channel.send(random.choice(responses))

    **if any(word in msg for word in jokes):**
      await message.channel.send(random.choice(comedy))

 
  if msg.startswith("+help"):
    await message.channel.send("Here is a Google Doc of all my commands! https://docs.google.com/document/d/1WKAG5rs0ZLQ7imIiQc9VxY1AkYmGmqM6SaXvAr5XSxI/edit?usp=sharing")

  if msg.startswith("+del mm"):
    encouragements = []
    if "encouragements" in db.keys():
      index = int(msg.split("+del mm",1)[1])
      delete_encouragment(index)
      encouragements = db["encouragements"]
    await message.channel.send(encouragements)

 
  if msg.startswith("+del joke"):
    jokes = []
    if "jokes" in db.keys():
      index = int(msg.split("+del joke",1)[1])
      delete_jokes(index)
      jokes = db[jokes]
    await message.channel.send(comedy)

   

  if msg.startswith("+list mm"):
    encouragements = []
    if "encouragements" in db.keys():
      encouragements = db["encouragements"] 
    await message.channel.send(encouragements)

 

  if msg.startswith("+responding"):
    value = msg.split("+responding ",1)[1]

    if value.lower() == "true":
      db["responding"] = True
      await message.channel.send("Responding is on.")
    else:
      db["responding"] = False
      await message.channel.send("Responding is off.")



keep_alive()
client.run(os.getenv('token'))

The line in bold is the line that I'm having an issue with. I suspect that the issue may be somewhere earlier in my code, but I'm unable to pinpoint where. I also think that there may be some other errors in my code contributing to this one. If anybody could help me fix these, that would be great.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
Inspire
  • 25
  • 2
  • 1
    have a read - https://stackoverflow.com/questions/8943933/variables-declared-outside-function you will need to use the global keyword. – Snake_py Nov 28 '21 at 01:09
  • line in bold??? Which line? At a **guess** it might be that a local `jokes` is shadowing(hiding) the global one - function sees a local jokes so ignores global one but then references before assignment. – JL Peyret Nov 28 '21 at 01:11
  • @JLPeyret Sorry, I realised that the line didn't come through in bold! I'm talking about this line: 'if any(word in msg for word in jokes): await message.channel.send(random.choice(comedy))' Could you please explain further? – Inspire Nov 28 '21 at 01:20
  • Snake_py looks on to something but ill look at the line now – JL Peyret Nov 28 '21 at 01:22
  • Yup not sure about your logic but Antonio and snake_py both are right about the problem. Thing is I am not sure what **you** are trying to do, so it could either be use global keyword or use different variable name. – JL Peyret Nov 28 '21 at 01:28
  • @JLPeyret Sorry, I'll try and make it clearer what I want to do. So I made a variable called jokes at the very beginning, and for every phrase in that variable, I want my bot to respond with a joke (which other users can add through the '+add joke' command. Basically, the issue is that there is apparently an error in the line where it says 'if any(word in msg for word in jokes)', and it says that the variable has been referenced before use, and I can't figure out why. I hope that helps clear it up a bit. – Inspire Nov 28 '21 at 01:40

2 Answers2

1

The function on_message defines its own jokes variable that shadows the global jokes variable. This happens inside the if statement that checks for msg.startsWith("+del joke"), namely when we set jokes=[]. If they are meant to be the same variable, add a statement global jokes inside the function, before the first usage of jokes:

async def on_message(message):
  global jokes
  # etc.

If not, use a different name for the local variable.

The following blog post illustrates a similar issue: https://www.programiz.com/python-programming/global-keyword

Antonio
  • 355
  • 1
  • 2
  • 13
  • It may be worth noting that the shadowing happens *regardless* of whether the assignment to `jokes` occurs or not. And it's not entirely clear to me, it may be that the `jokes = ` assignments in that code are supposed to be rewriting the global `jokes`, rather than doing something with local variables. So `global jokes` might be the proper fix. – Blckknght Nov 28 '21 at 01:32
  • @Antonio, I'm not sure I understand what you mean. The function on_message doesn't define its own jokes variable (unless I'm looking at something different). Could you please elaborate? – Inspire Nov 28 '21 at 01:33
  • Inside the `if msg.startswith("+del joke")`, we have `jokes=[]`. I think that this shadows the global `jokes` variable defined at the top of the file. If they are meant to be the same variable, use the `global` keyword. If not, use a different name. – Antonio Nov 28 '21 at 01:39
  • @Antonio, I think I've understood what you're saying, but what about the syntax error that occurs when I do 'global jokes = []'. I think I'm missing something really obvious, but I'm not sure what it is. – Inspire Nov 28 '21 at 01:48
  • @Inspire 2 different lines `global jokes` then `jokes = []`, not `global jokes = []` this is basically telling python - that `jokes`, it's on the global variable, not to be assigned to the local function namespace. it would also be best if you just extracted the 4-5 lines of stuff that's of interest to a minimal script, the rest of the stuff is just irrelevant to the question. – JL Peyret Nov 28 '21 at 01:53
  • @JLPeyret I think I understood you and I tried that, but it's now saying that: name 'jokes' is used prior to global declaration. What am I doing wrong? – Inspire Nov 28 '21 at 01:56
  • I think the `global jokes` statement needs to appear before any use of `jokes` inside the function. I've updated the answer to reflect that. – Antonio Nov 28 '21 at 02:01
  • @Antonio @, I've tried what you have suggested, yet it shows the same error. I'm really confused. Could you write what the snippet of the code should be and send it so I can understand it better? I'd really appreciate it. – Inspire Nov 28 '21 at 02:10
0

Like I said, make the stuff very simple and work back from that.

The following replicates your error:

jokes = ["funny"]

def on_message(message):


    if any(jokes):
        print("ha ha")

    if message.startswith("+del joke"):
        jokes = []

on_message("add joke")    
on_message("del joke")    

output:

UnboundLocalError: local variable 'jokes' referenced before assignment

This is still the same error, because global comes too late:

jokes = ["funny"]

def on_message(message):


    if any(jokes):
        print("ha ha")

    global jokes

    if message.startswith("+del joke"):
        jokes = []

on_message("add joke")    
on_message("del joke")    

output:

SyntaxError: name 'jokes' is used prior to global declaration

To fix it, you need to tell python about it being a global before you use that condition on jokes:

jokes = ["funny"]

def on_message(message):

    global jokes

    if any(jokes):
        print("ha ha")


    if message.startswith("+del joke"):
        jokes = []

on_message("add joke")    
on_message("del joke")    

output:

ha ha
ha ha
JL Peyret
  • 10,917
  • 2
  • 54
  • 73
  • yep I tried that and it worked. But something happened which I was worried about. Clearing that error made way for another error (of the same type0, but with the variable comedy. It says it has been referenced before assignment. I've tried to fix this, but I can't figure out how. This is why I had sent all of my code in the question. – Inspire Nov 28 '21 at 02:22
  • well, we are not going to fix all your code for you. we can explain how one particular error needs to be fixed and the logic behind that, but untangling the same error 3 different times in a big pile of code is not something you should expect to happen very often here. you probably need to comment out the bits of codes that cause errors and fix one error at a time. sorry. – JL Peyret Nov 28 '21 at 02:55