4

I get an UnboundLocalError because I use a template value inside an if statement which is not executed. What is the standard way to handle this situation?

class Test(webapp.RequestHandler):
    def get(self):      
        user = users.get_current_user()
        if user:
            greeting = ('Hello, ' + user.nickname())
        else:
            self.redirect(users.create_login_url(self.request.uri))
...

        template_values = {"greeting": greeting,
                       }

Error:

UnboundLocalError: local variable 'greeting' referenced before assignment
Zeynel
  • 13,145
  • 31
  • 100
  • 145
  • 3
    Is there some reason you can't just do `greeting = None` (or a reasonable default) before the `if ... else` bit? – Joe Kington Oct 29 '10 at 03:27
  • 1
    I don't know webapp, but I expect you want to do `return self.redirect...` anyway. – Daniel Roseman Oct 29 '10 at 08:07
  • @Daniel Roseman: Sorry, I don't understand what `return self.redirect` does. Can you explain? I used `greeting=None` as suggested by Joe Kington and that works. Thanks. – Zeynel Oct 29 '10 at 15:45
  • It should say `return self.redirect(...` where it currently says `self.redirect(...`, because this causes `get` to stop running and give back the `self.redirect` result to the caller (first linked duplicate explains `return`). This is necessary because the rest of the code cannot run without a `greeting` value set (second linked duplicate). – Karl Knechtel Feb 07 '23 at 02:42

2 Answers2

3

Just Switch:

class Test(webapp.RequestHandler):
    def err_user_not_found(self):
        self.redirect(users.create_login_url(self.request.uri))
    def get(self):      
        user = users.get_current_user()
        # error path
        if not user:
            self.err_user_not_found()
            return

        # happy path
        greeting = ('Hello, ' + user.nickname())
        ...
        template_values = {"greeting": greeting,}
fabrizioM
  • 46,639
  • 15
  • 102
  • 119
  • Thanks for the answer. I used `greeting=None` for now; but when I am ready to deploy the app I may use this version. What does `return` do? Why is it necessary? – Zeynel Oct 29 '10 at 15:51
  • @Zeynel It exits from the routine, otherwise the interpreter will continue executing all the following statements. – fabrizioM Oct 29 '10 at 18:19
  • The key point here is the `return`, which prevents the rest of the function from executing once the error has been detected and a redirect triggered. Everything else is just refactoring. – Karl Knechtel Feb 07 '23 at 02:39
2

I guess I need to explain the problem first: in creating template_values, you use a greeting variable. This variable will not be set if there is no user.

There isn't a standard way to handle this situation. Common approaches are:

1. make sure that the variable is initialized in every code path (in your case: including the else case)
2. initialize the variable to some reasonable default value at the beginning
3. return from the function in the code paths which cannot provide a value for the variable.

Like Daniel, I suspect that after the redirect call, you are not supposed to produce any output, anyway, so the corrected code might read

class Test(webapp.RequestHandler):
  def get(self):      
    user = users.get_current_user()
    if user:
        greeting = ('Hello, ' + user.nickname())
    else:
        self.redirect(users.create_login_url(self.request.uri))
        return
...

    template_values = {"greeting": greeting,
                   }
Martin v. Löwis
  • 124,830
  • 17
  • 198
  • 235
  • Thanks. It seemed the second option is the easiest so I chose `greeting=None`. Why is `return` necessary? – Zeynel Oct 29 '10 at 15:53
  • 1
    self.redirect will only instruct webapp to send a redirect - it is a regular function and cannot really abort the execution of get() (except when it would raise an exception). So if you don't want to / must no perform any further action after the redirect, you really should return from the get right away, and avoid performing more activity (which then is either incorrect or unneeded). – Martin v. Löwis Oct 29 '10 at 17:08