views:

342

answers:

6

This module is part of a simple todo app I made with Python...

def deleteitem():
             showlist()
             get_item = int(raw_input( "\n Enter number of item to delete: \n"))
             f = open('todo.txt')
             lines = f.readlines()
             f.close()
             lines[get_item] = ""
             f = open('todo.txt','w')
             f.writelines(lines)
             f.close()
             showlist()

The number of lines in f obviously changes as items are added to the list... Problem here is that for example if a user enters '10' when there are only 9 lines in the file ( or anything else not in range) , it exits as expected with :

IndexError: list assignment index out of range

What can I add to the module so as to have it prompt user to enter an item within the range? I am assuming maybe a Try block ... Or is there a way to catch an exception.. I am guessing there is an easy way to do this...

+3  A: 

Either catch IndexError when indexing or check the len() of the list beforehand.

Ignacio Vazquez-Abrams
+3  A: 

First read the file, and then ask user in a loop, until the answer is acceptable:

while True:
    get_item = int(raw_input( "\n Enter number of item to delete: \n"))
    if get_item >=0 and get_item < len(lines):
        break

That will, of course, break when the file is empty and doesn't give any hint about the acceptable values to the user. But let's keep some exercise for you.

Jacek Konieczny
Add a nice output that states the problem to the user.
Don Johe
A: 
def deleteitem():
             showlist()
             get_item = int(raw_input( "\n Enter number of item to delete: \n"))
             f = open('todo.txt')
             lines = f.readlines()
             f.close()
             try:
                 lines[get_item] = ""
             except Exception,err: 
                 print err
             f = open('todo.txt','w')
             f.writelines(lines)
             f.close()
             showlist()
Bare excepts have a few valid uses, but this isn't one of them.
Roger Pate
but its sufficient for his purpose and it does the job. Anymore comments?
No, it doesn't. It will silently swallow KeyboardInterrupt, for example, if you were unlucky enough to get it at the right (or wrong) time. As much as possible, I design my code so that it works as expected and desired even in such "unlucky" situations and could not ethically recommend this code. Is it even that hard for you to correct it? Change "except:" to "except IndexError:".
Roger Pate
`except` catches all exceptions, so what do you mean by silently "swallow" KeyboardInterrupt.
@levis: KeyboardInterrupt is an exception it would be *wrong* to catch in this case. Instead of passing the exception up, your code ignores/swallows it---hides that it ever existed.
Roger Pate
+1  A: 

Judicious changes to your current code:

def deleteitem():
  showlist()

  with open("todo.txt") as f:
    lines = f.readlines()
  if len(lines) == 0:  # completely empty file
    return  # handle appropriately
  prompt = "Enter number to delete (1-%d), or 0 to abort: " % len(lines)
  while True:
    input = raw_input(prompt)
    try:
      input = int(input, 10)
    except ValueError:
      print "Invalid input."
    else:
      if 0 <= input <= len(lines):
        break
      print "Input out of range."
  if input == 0:
    return
  input -= 1  # adjust from [1,len] to [0,len)

  #del lines[input]  # if you want to remove that line completely
  lines[input] = "\n"  # or just make that line blank (what you had)

  with open("todo.txt", "w") as f:
    f.writelines(lines)

  showlist()
Roger Pate
Thanks, this worked.I am using Python 2.5.x..so I was getting hung up on 'with'.I added " from future__import__ with_statement " to the script and was all set.I think in your code, the line " if len(lines) == 0: "may need to be indented? ... I was getting an error until I did that
CaseyIT
@skylarking: It shouldn't need indentation, and that part should work fine as I have it above. Perhaps you accidentally miscopied?
Roger Pate
That's very probable I've made a mistake there.... I did post the full todo app as an answer here if you are curious. I am sure there's lots of improvements that could happen there as well
CaseyIT
A: 

Try something like this:

def deleteitem():

showlist()
f = open('todo.txt')
lines = f.readlines()
f.close()
if len(lines) == 0:
    print "File is empty!"
    return False
print "File has %d items\n" % len(lines)
item = 0
while item < len(lines):
    item = raw_input( "\n Enter number of item to delete(0-%d): \n" % len(lines))
    item = int(item) # because of the width of the code
f = open('todo.txt','w')
f.write(lines[0:item-1])
f.write(lines[item::])
f.close()
showlist()
lugte098
A: 

For what it's worth.... I'll put the code to my todo.py program here... It's just something I run from a Terminal in OS X to keep control of stuff I need to do at work...I am sure it's horribly un-pythonic,inefficient and everything else...but maybe it'll be of use to some one who stumbles across this thread :

from __future__ import with_statement
import sys
import os
import fileinput

os.system('clear')

print ("##############          TO DO LIST       ############")
print ("##############                           ############")

def showlist():
    os.system('clear')
    print ("############  Current To Do List  ######")
    print ("########################################")

    get_list = open('todo.txt')
    entire_list = get_list.readlines()
    for i in range (len(entire_list)):
        print i, entire_list[i]
    get_list.close()
    print ("########################################")
    print ("########################################")

def appendlist():
    print ("#######################################")
    print ("#######################################")


    addtolist = str( raw_input("Enter new item:  \n"))
    thelist = open('todo.txt', 'a')
    thelist.write(str(addtolist))
    thelist.write(str('\n'))
    thelist.close()  
    showlist()


def deleteitem():
    showlist()

        with open("todo.txt") as f:
            lines = f.readlines()
            if len(lines) == 0:  
                return  
        prompt = "Enter number to delete or '0' to abort: " 
        while True:
                input = raw_input(prompt)
                try:
                    input = int(input, 10)
                except ValueError:
                    print "Invalid input."
                else:
                    if 0 <= input <= len(lines):
                        break
                    print "Input out of range."
        if input == 0:
                  return

        lines[input] = "" 

            with open("todo.txt", "w") as f:
                f.writelines(lines)

        showlist()

while True:

    askme = raw_input("\nDo you want to:\n(S)ee list\n(A)ppend list\n(D)elte from list\n(Q)Quit?\n")
    print str('\n')

    if askme == "S":
        showlist()
    elif askme == "A":
        appendlist()
    elif askme == "D":
        deleteitem()

    elif askme == "Q":
        sys.exit()
    else: 
        print ("Try again?")

print ("#######################################")
print ("#######################################")
CaseyIT
You're either mixing tabs and spaces, or the indentation got screwed up when posting on SO.
Roger Pate
I think I went for the trifecta and managed to do all three of those things..Just edited it to clean it up.
CaseyIT