UnboundLocalError in TKinter, SQLAlchemy script.

Chris Kavanagh ckava3 at gmail.com
Wed Mar 18 15:42:12 EDT 2015


On Wednesday, March 18, 2015 at 8:02:14 AM UTC-4, Steven D'Aprano wrote:
> On Wed, 18 Mar 2015 01:41 pm, Chris Kavanagh wrote:
> 
> > I have a simple script that takes user input (for an Employee) such as
> > name, age, etc then puts in an sqlite3 database. The script worked fine
> > until I realized one problem. The age input field is defined in SQLAlchemy
> > as an Integer, so if a user inputs a string instead of a number in that
> > field, an error will occur (in IDLE). . .
> > 
> > So, I put a try: except clause in the code for the age field in the
> > add_data method. . .
> > try:
> >             age = self.age_var.get()
> >         except ValueError:
> >             showinfo("Error:", "Please Enter A Number In Age Field.")
> > 
> > If the user inputs a string (instead of an Int) the showinfo dialogue box
> > opens as it should, but when the user clicks "ok" in the box, I get the
> > error "UnboundLocalError: local variable 'age' referenced before
> > assignment".
> 
> As much as I love guessing games, I reckon I have about a 2/3 chance of
> guessing right, but you will get MUCH better results by posting the
> *entire* traceback, not just the last line. In particular, look at the line
> of code shown. That's where the problem expresses itself, and that may give
> good hints as to where the problem actually is.
> 
> 
> > I tried using a default value above the try: except clause 
> > (age=0), which corrects the error, but causes "0" to be saved in the
> > database instead of letting the user choose another value. I want to
> > figure why I get the error (with the try: except clause) and what exactly
> > to do about it. Thanks in advance for any help!
> 
> And again, guessing games are lots of fun, but showing us the actual code is
> better. You might think it is "obvious" what you are talking about, but the
> change that you think is obvious and the change that I think is obvious are
> not necessarily that same.
> 
>  
> > Here's the original code (without the try: except clause above). . .Just
> > put the try: except clause in the age variable in the add_data method as
> > shown above to get the error.
> 
> We don't need to see almost 300 lines of irrelevant GUI code that has
> nothing to do with the problem. Here's the add_data method:
> 
> 
> >     def add_data(self):
> >         name = self.name_var.get()
> >         age = self.age_var.get()
> >         addr = self.address_var.get()
> >         city = self.city_var.get()
> >         state = self.state_var.get()
> >         zip = self.zip_var.get()
> >         ssn = self.ssn_var.get()
> >         phone = self.phone_var.get()
> >         cell = self.cell_var.get()
> >         # create new Employee in .db
> >         new_person = Employee(name=name, age=age, address=addr, city=city,
> >                               state=state, zip=zip, ssn=ssn, phone=phone,
> >                               cell=cell) 
> >         session.add(new_person)
> >         session.commit()
> >         session.close()
> >         self.callback()
> >         return
> 
> Most of that is irrelevant too. My guess is that it can be simplified to
> this:
> 
>     def add_data(self):
>         age = self.age_var.get()
>         new_person = Employee(name=name, age=age, address=addr, city=city,
>                               state=state, zip=zip, ssn=ssn, phone=phone,
>                               cell=cell)
> 
> 
> Where are we supposed to put the try: except clause? My guess is:
> 
>     def add_data(self):
>         try:
>             age = self.age_var.get()
>         except ValueError:
>             showinfo("Error:", "Please Enter A Number In Age Field.")
>         new_person = Employee(name=name, age=age, address=addr, city=city,
>                               state=state, zip=zip, ssn=ssn, phone=phone,
>                               cell=cell)
> 
> and the error occurs on the call to Employee. Is that right? 
> 
> Follow the program logic. The line of code:
> 
>     age = self.age_var.get()
> 
> tries to run, and fails. Since the line of code never completes, "age" never
> gets a value set. Then the dialog box is shown, and your program blindly
> continues. Eventually it reaches the Employee() line, and tries to use the
> value of "age". But it doesn't exist, so you get the UnboundLocalVariable
> error.
> 
> The right solution here is to set the age_var field in the GUI to force it
> to be an integer. By the time you get to running the add_data method, it is
> too late to pause and let the user re-type a new value in the field. You
> could try this:
> 
> http://tkinter.unpythonic.net/wiki/ValidateEntry
> 
> 
> Another option is to make the add_data method simply halt when the age is
> not an integer, and do nothing. Then the user will have to click the Add
> button again to make it work:
> 
> 
>     def add_data(self):
>         try:
>             age = self.age_var.get()
>         except ValueError:
>             showinfo("Error:", "Please Enter A Number In Age Field.")
>             return  # Return early, do nothing.
>         new_person = Employee(name=name, age=age, address=addr, city=city,
>                               state=state, zip=zip, ssn=ssn, phone=phone,
>                               cell=cell)
> 
> 
> 
> 
> 
> -- 
> Steven

While I appreciate the help greatly I thought I had put the entire traceback of the error. I was posting here and on StackOverflow, and suppose I got confused. 

 2nd, you say you "don't want to play guessing games", yet complain about "300 lines of irrelevant code", lol. Which way is it? Do you want the code, or not? How do I know what's relevant or irrelevant when I'm clearly confused? On Stack, if you don't post the entire code, you are asked to do so. I would think it would be the same procedure here.

Anyways, thanks again for the advice.



More information about the Python-list mailing list