Araf
Araf

Reputation: 353

Access data files from within a python package

I am trying to play a wav file based on the character the user inputs. My project structure looks like:

mypkg/
 |
 | mypkg/
    | 
    | __init__.py
    | code.py
    | sound/
        |
        | A.wav
        | B.wav
        | ...
 |
 | setup.py

I have added the following in setup.py:

package_dir={'mypkg': 'mypkg'},
package_data={'mypkg': ['sound/*.wav']}

My code.py looks like:

files = {
        'A': 'sound/A.wav',
        'B': 'sound/B.wav',
         ...
}
c = raw_input()
f = files.get(c, '?')
...playing the wave file code...

I know 'A': 'sound/A.wav', is wrong. The problem is everything runs fine if I use the code as a script, but I get an IO error if I run setup.py and then import this as a module in the console. Specifically: IOError: [Errno 2] No such file or directory: 'sound/S.wav'

I know I have to use pkgutil.get_data() but then how can I add the correct path to the files in my files dictionary. What should my code.py look like?

Upvotes: 4

Views: 2745

Answers (2)

emcek
emcek

Reputation: 535

There is another way but working with data_fles from setup.py:

setup.py

setup(name='dcspy',
  version=__version__,
  ...
  data_files=[('dcspy_data', ['images/dcspy.ico'])],
  ...

When you pip install will put data_files here:

$ pip uninstall dcspy
Found existing installation: dcspy 1.1.2
Uninstalling dcspy-1.1.2:
 Would remove:
  d:\python38\dcspy_data\dcspy.ico
  d:\python38\lib\site-packages\dcspy-1.1.2.dist-info\*
  d:\python38\lib\site-packages\dcspy\*
  d:\python38\scripts\dcspy.exe
Proceed (y/n)? y

you can access them in your package like:

root = tk.Tk()
root.iconbitmap(f'{sys.prefix}/dcspy_data/dcspy.ico')

Information: 2.7. Installing Additional Files

Upvotes: 2

Anand S Kumar
Anand S Kumar

Reputation: 90999

The issue is that, when you run a script, the current location of that script is where you run it from, assume you run the script from a totally different location using absolute path , then the current location inside that script is the location you were in when you ran the script, not the location of the script.

For your example, in your code.py , you need to get the location of that python file and then append the data file to that location, before using it.

To get the location of the python file being run, you can use __file__ , or the better - os.path.realpath(__file__) , you need to understand that __file__ would give the complete path of the file, to extract the directory you have to use - os.path.dirname() .

Then your code would look like -

pt = os.path.dirname(os.path.realpath(__file__))
files = {
        'A': os.path.join(pt, 'sound/A.wav'),
        'B': os.path.join(pt, 'sound/B.wav'),
         ...
}

Upvotes: 4

Related Questions