Ziyuan Ma Ziyuan Ma - 1 month ago 10
Python Question

ValueError: need more than 3 values to unpack

I'm struggling about this

ValueError
, it happens when I want to define an
init_db
function with resetting the database and adding some data from local document (
hardwarelist.txt
), the code was:

def init_db():
"""Initializes the database."""
db = get_db()
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
with open('hardwarelist.txt') as fl:
for eachline in fl:
(model,sn,user,status)=eachline.split(',')
db.execute('insert into entries (model,sn,user,status) values (?, ?, ?, ?)',
(model,sn,user,status))
fl.close()
db.commit()


And the error was:

File "/home/ziyma/Heroku_pro/flaskr/flaskr/flaskr.py", line 48, in init_db
(model,sn,user,status)=eachline.split(',')
ValueError: need more than 3 values to unpack


What should I do?

Answer

One of my mentors told me "If half your code is error handling, you aren't doing enough error handling." But we can leverage python's exception handling to make the job easier. Here, I've reworked your example so that if an error is detected, a message is displayed, and nothing is committed to the database.

When you hit the bad line, its printed and you can figure out what's wrong from there.

import sys

def init_db():
    """Initializes the database."""
    db = get_db()
    with app.open_resource('schema.sql', mode='r') as f:
        db.cursor().executescript(f.read())
    with open('hardwarelist.txt') as fl:
        try:
            for index, eachline in enumerate(fl):
               (model,sn,user,status)=eachline.strip().split(',')
               db.execute('insert into entries (model,sn,user,status) values (?, ?, ?, ?)',
                          (model,sn,user,status))
            db.commit()
        except ValueError as e:
            print("Failed parsing {} line {}: {} ({})".format('hardwarelist.txt',
                index, eachline.strip(), e), file=sys.stderr)

            # TODO: Your code should have its own exception class
            # that is raised. Your users would catch that exception
            # with a higher-level summary of what went wrong.
            raise

You should expand that exception handler to catch exceptions from your database code so that you can catch more errors.

As a side note, you need to strip the line before splitting to remove the \n newline character.

UPDATE

From the comments, here's an example on splitting multiple forms of the comma. In this case its Unicode FULLWIDTH COMMA U+FF0C. Whether you can enter unicode directly into your python scripts depends on your text editor and etc..., but that comma could be represented by "\uff0c" or ",". Anyway could can use a regular expression to split on multiple characters.

I create the text using unicode escapes

>>> text='a,b,c\uff0cd\n'
>>> print(text)
a,b,c,d

and I can write the regex with excapes

>>> re.split('[,\uff0c]', text.strip())
['a', 'b', 'c', 'd']

or by copy/paste of the alternate comma character

>>> re.split('[,,]', text.strip())
['a', 'b', 'c', 'd']