Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 3 - ValueError: not enough values to unpack (expected 3, got 2)

I have a problem with my Python 3 program. I use Mac OS X. This code is running properly.

# -*- coding: utf-8 -*-
#! python3
# sendDuesReminders.py - Sends emails based on payment status in spreadsheet.

import openpyxl, smtplib, sys


# Open the spreadsheet and get the latest dues status.
wb = openpyxl.load_workbook('duesRecords.xlsx')
sheet = wb.get_sheet_by_name('Sheet1')

lastCol = sheet.max_column
latestMonth = sheet.cell(row=1, column=lastCol).value

# Check each member's payment status.
unpaidMembers = {}
for r in range(2, sheet.max_row + 1):
payment = sheet.cell(row=r, column=lastCol).value
if payment != 'zaplacone':
    name = sheet.cell(row=r, column=2).value
    lastname = sheet.cell(row=r, column=3).value
    email = sheet.cell(row=r, column=4).value
    unpaidMembers[name] = email


# Log in to email account.
smtpObj = smtplib.SMTP_SSL('smtp.gmail.com', 465)
smtpObj.ehlo()
smtpObj.login('[email protected]', '1234')


# Send out reminder emails.
for name, email in unpaidMembers.items()
body = "Subject: %s - przypomnienie o platnosci raty za treningi GIT Parkour. " \
       "\n\nPrzypominamy o uregulowaniu wplaty za uczestnictwo: %s w treningach GIT Parkour w ." \
       "\n\nRecords show  that you have not paid dues for %s. Please make " \
       "this payment as soon as possible."%(latestMonth, name, latestMonth)
print('Sending email to %s...' % email)
sendmailStatus = smtpObj.sendmail('[email protected]', email, body)

if sendmailStatus != {}:
    print('There was a problem sending email to %s: %s' % (email,
    sendmailStatus))
smtpObj.quit()enter code here

Problems starts when I am trying to add next value to the for loop.

# Send out reminder emails.
for name, lastname, email in unpaidMembers.items()
body = "Subject: %s - przypomnienie o platnosci raty za treningi GIT Parkour. " \
       "\n\nPrzypominamy o uregulowaniu wplaty za uczestnictwo: %s %s w treningach GIT Parkour w ." \
       "\n\nRecords show  that you have not paid dues for %s. Please make " \
       "this payment as soon as possible."%(latestMonth, name, lastname, latestMonth)
print('Sending email to %s...' % email)
sendmailStatus = smtpObj.sendmail('[email protected]', email, body)

Terminal shows error:

Traceback (most recent call last):
    File "sendDuesEmailReminder.py", line 44, in <module>
        for name, email, lastname in unpaidMembers.items():
ValueError: not enough values to unpack (expected 3, got 2)
like image 689
Jakub Kłos Avatar asked Feb 15 '17 20:02

Jakub Kłos


Video Answer


2 Answers

You probably want to assign the lastname you are reading out here

lastname = sheet.cell(row=r, column=3).value

to something; currently the program just forgets it

you could do that two lines after, like so

unpaidMembers[name] = lastname, email

your program will still crash at the same place, because .items() still won't give you 3-tuples but rather something that has this structure: (name, (lastname, email))

good news is, python can handle this

for name, (lastname, email) in unpaidMembers.items():

etc.

like image 199
Paul Panzer Avatar answered Sep 18 '22 15:09

Paul Panzer


1. First should understand the error meaning

Error not enough values to unpack (expected 3, got 2) means:

a 2 part tuple, but assign to 3 values

and I have written demo code to show for you:


#!/usr/bin/python
# -*- coding: utf-8 -*-
# Function: Showing how to understand ValueError 'not enough values to unpack (expected 3, got 2)'
# Author: Crifan Li
# Update: 20191212

def notEnoughUnpack():
    """Showing how to understand python error `not enough values to unpack (expected 3, got 2)`"""
    # a dict, which single key's value is two part tuple
    valueIsTwoPartTupleDict = {
        "name1": ("lastname1", "email1"),
        "name2": ("lastname2", "email2"),
    }

    # Test case 1: got value from key
    gotLastname, gotEmail = valueIsTwoPartTupleDict["name1"] # OK
    print("gotLastname=%s, gotEmail=%s" % (gotLastname, gotEmail))
    # gotLastname, gotEmail, gotOtherSomeValue = valueIsTwoPartTupleDict["name1"] # -> ValueError not enough values to unpack (expected 3, got 2)

    # Test case 2: got from dict.items()
    for eachKey, eachValues in valueIsTwoPartTupleDict.items():
        print("eachKey=%s, eachValues=%s" % (eachKey, eachValues))
    # same as following:
    # Background knowledge: each of dict.items() return (key, values)
    # here above eachValues is a tuple of two parts
    for eachKey, (eachValuePart1, eachValuePart2) in valueIsTwoPartTupleDict.items():
        print("eachKey=%s, eachValuePart1=%s, eachValuePart2=%s" % (eachKey, eachValuePart1, eachValuePart2))
    # but following:
    for eachKey, (eachValuePart1, eachValuePart2, eachValuePart3) in valueIsTwoPartTupleDict.items(): # will -> ValueError not enough values to unpack (expected 3, got 2)
        pass

if __name__ == "__main__":
    notEnoughUnpack()

using VSCode debug effect:

notEnoughUnpack CrifanLi

2. For your code

for name, email, lastname in unpaidMembers.items():

but error ValueError: not enough values to unpack (expected 3, got 2)

means each item(a tuple value) in unpaidMembers, only have 1 parts:email, which corresponding above code

    unpaidMembers[name] = email

so should change code to:

for name, email in unpaidMembers.items():

to avoid error.

But obviously you expect extra lastname, so should change your above code to

    unpaidMembers[name] = (email, lastname)

and better change to better syntax:

for name, (email, lastname) in unpaidMembers.items():

then everything is OK and clear.

like image 34
crifan Avatar answered Sep 18 '22 15:09

crifan