[Tutor] Deleting items from a shelve file when items are unknown

Cameron Simpson cs at cskk.id.au
Sat Oct 19 18:09:31 EDT 2019


On 18Oct2019 23:03, James Austin <james.londonsw15 at gmail.com> wrote:
>I am quite new  to Python, so please bare with me.

I'd rather remain clothed, but I'm happy to bear with you.

>I am developing a basic clipboard application that saves text to a 
>keyword and lists the saved items for the user. Users will then be 
>able to paste saved text into an external  application by using the 
>keyword they first assigned. Saved data is stored in a Shelve file.

I _presume_ you mean Shelf objects from the "shelve" module? Please 
verify that.

>I have a working prototype for the 'save' and 'list' features of the 
>program. Currently this program is command line only.

Command line programmes are easy to use with scripts and easier to debug 
than GUIs. Always a good starting point.

>Before adding the 'paste' feature, I am working on implementing a way 
>for users to delete keywords and text they no longer want. This is 
>where I hope the list can advise  please. I am trying to write code 
>that will allow the user to delete **any** keyword that they find in 
>the list. A portion of my code is below and below that is a brief 
>summary of what I have tried so far:
>
>---snip---
># Delete keywords/comments
>elif len(sys.argv) == 2 and sys.argv[1] == 'delete':
>  if clipboardShelf[sys.argv[2]] in clipboardShelf.keys():
>   clipboardShelf.pop()

Problem 1: if you have sys.argv[2], then len(sys.argv) is at least 3 
(elements 0,1,2).

Personally I tend to pop things off sys.argv progressively so that they 
can get nice names:

    cmd = sys.argv.pop(0)   # command name
    op = sys.argv.pop(0)    # operation
    if op == 'delete':
        key = sys.argv.pop(0)

This has the advantage of not hardwiring argument positions into your 
code. (Suppose you latter add some option parsing ahead of the 'delete' 
operation word?) It also mades the code more readable ("key" instead of 
"sys.argv[2]").

Anyway, to the code again:

>  if clipboardShelf[sys.argv[2]] in clipboardShelf.keys():
>   clipboardShelf.pop()

A Shelf is a mutable mapping of keys to values. So
clipboardShelf[sys.argv[2]] is a clipboard value.  That will not be in 
the keys. You probably mean:

    if sys.argv[2] in clipboardShelf.keys():

Then you go: clipboardShelf.pop(). I imagine your intent here it to 
remove the clipboard entry with key sys.argv[2], but you do not tell the 
pop method what key to remove. If clipboardShelf really is a mapping you 
can go:

    del clipboardShelf[sys.argv[2]]

>This code does not throw errors when tested with: python clipboard.py.  

If you attached clipboard.py, it is gone. This list is text only and 
discards attachments. Just paste the code into the message body. If the 
cde is long, paste it at the end with your discussion up front.

>However, when I run python clipboard.py list, the keyword remains in 
>the shelve file.
>
>Although my understanding is limited, I believe, from what I have 
>read, that shelve files act like dictionaries. However, using the 
>'del' option yields the same result.

Maybe there's some method to _save_ the new state of the clipboard?

I see that a shelve.Shelf object has .sync and /close methods. You need 
to use there is the Shelf is to be saved back to the file.

>I have tried several variations including the following 'for' loop:
>---snip---
>elif len(sys.argv) == 2 and sys.argv[1] == 'delete':
>  for key in clipboardShelf.keys():
>   del clipboardShelf['']

This deletes the key '' many times, not the key specified by "key".

Also, if is not safe to modify a mapping while you are iterating over 
it. This is a general rule, but in this specific case .keys() usually 
returns a generator which yields keys. If you modify the mapping while 
using that generator it may skip some keys or behave in other unexpected 
ways. try:

    keys = list(clipboardShelf.keys())
    for key in keys:
        del clipboardShelf[key]

i.e. run the generator completely and get a list, and _then_ modify the 
mapping.

>I have also tried signifying the unknown key with empty brackets.

Is deleting an unknown key a sensible concept?

I see the Shelf class is a context manager. You chould wrap your command 
line parse code in a with statement:

    cmd = sys.argv.pop(0)
    with shelve.open(filename, writeback=True) as clipboardShelf:
        do delete, etc etc

When you exit the with suite the shelf gets saved.

Cheers,
Cameron Simpson <cs at cskk.id.au>


More information about the Tutor mailing list