How can I open a python shelve file in a specific directory

2.5k views Asked by At

I am working on Ch. 8 of "Automate the Boring Stuff With Python", trying to extend the Multiclipboard project. Here is my code:

#! /usr/bin/env python3

# mcb.pyw saves and loads pieces of text to the clipboard
# Usage:        save <keyword> - Saves clipboard to keyword.
#               <keyword> - Loads keyword to the clipboard.
#               list - Loads all keywords to clipboard.
#               delete <keyword> - Deletes keyword from shelve.

import sys, shelve, pyperclip, os

# open shelve file
dbFile = os.path.join('Users', 'dustin', 'Documents', 'repos', 'python', 'mcbdb')
shelfFile = shelve.open(dbFile)


# Save clipboard content
if len(sys.argv) == 3 and sys.argv[1].lower() == 'save':
   shelfFile[sys.argv[2]]= pyperclip.paste()

# Delete choosen content
elif len(sys.argv) == 3 and sys.argv[1].lower() == 'delete':
        if sys.argv[2] in list(shelfFile.keys()):
            del shelfFile[sys.argv[2]]
            print('"' + sys.argv[2] + '" has been deleted.')
        else:
            print('"' + sys.argv[2] + '" not found.')
elif len(sys.argv) == 2:
    # List keywords
    if sys.argv[1].lower() == 'list':
        print('\nAvailable keywords:\n')
        keywords = list(shelfFile.keys())
        for key in sorted(keywords):
            print(key)
    # Load content         
    elif sys.argv[1] in shelfFile:
        pyperclip.copy(shelfFile[sys.argv[1]])
    else:
        # Print usage error
        print('Usage:\n1. save <keyword>\n2. <keyword>\n' +
                '3. list\n4. delete <keyword>')
        sys.exit()

# close shelve file
shelfFile.close()

I have added this program to my path and would like to use it from whatever directory I am currently working in. The problem is that shelve.open() creates a new file in the current working directory. How can I have one persistent directory?

2

There are 2 answers

0
Nick T On BEST ANSWER

Your

dbFile = os.path.join('Users', 'dustin', 'Documents', 'repos', 'python', 'mcbdb')

will turn into something like 'Users/dustin/Documents/repos/python/mcbdb' so if you run it from /Users/dustin/ it'll point to /Users/dustin/Users/dustin/Documents/repos/python/mcbdb which is probably not what you want.

If you use an absolute path, something rooted with either / or X:\ (OS-dependent) will keep that "specific directory".

I might recommend something else though, get the user's home directory using ~ and os.path.expanduser:

dbFile = os.path.expanduser('~/.mcbdb')
0
Sean On

3 years later and I've stumbled across the same problem. As you stated

shelfFile = shelve.open('fileName')

saves the shelf file to the cwd. Depending on how you start your script the cwd changes and thus the file may get saved in different places.

Of course you can say

shelfFile = shelve.open('C:\an\absolute\path')

but that's problematic if the original script is moved to another directory.

Therefore I've come up with this:

from pathlib import Path
shelfSavePath = Path(sys.argv[0]).parent / Path('filename')
shelfFile = shelve.open(fr'{shelfSavePath}')

This will save the shelf file in the same directory the python script is in.

Explanation:

On windows sys.argv[0] is the full pathname of the script which will probably look something like this:

C:\Users\path\to\script.py

Look here for documentation on sys.argv

In this example

Path(sys.argv[0]).parent

would result in

C:\Users\path\to

to which we add Path('filename') by using the / Operator.

As a result this would give us:

C:\Users\path\to\filename

and thus always save the shelf file in the same directory as the script regardless of what directory the script is in.

Look here for documentation on pathlib