Search code examples
pythonsetuptoolsdistutilspython-modulesetup.py

How can I make sure that python finds the necessary data files?


Please consider this script:

$ tree my_application 
my_application
├── my_application
│   ├── sound.mp3
│   ├── __init__.py
│   ├── my_application.py
│   ├── my_application.pyc
│   └── __pycache__
│       ├── __init__.cpython-34.pyc
│       └── my_application.cpython-34.pyc
├── my_application.egg-info
│   ├── dependency_links.txt
│   ├── entry_points.txt
│   ├── PKG-INFO
│   ├── requires.txt
│   ├── SOURCES.txt
│   └── top_level.txt
├── run.py
├── MANIFEST.in
└── setup.py

my_application.py is a script that just plays sound.mp3 using mplayer:

class Sound():
    def __init__(self):
        self.cmd = ["mplayer", "sound.mp3"]            
    def play(self):
        subprocess.Popen(self.cmd)

setup.py is your classical setup.py file, with a console_script to my_application:main.

MANIFEST.in contains a reference to sound.mp3 to make sure it gets copied when running setup.py:

include my_application/sound.mp3
global-exclude *.pyc

run.py contains a small piece of code to run the main() function of my_application:

from my_application import main

if __name__ == "__main__":
    main()

There's an __init__.py file too, so that the main() function is correctly shown to the 'outside world':

from .my_application import main

__all__ = ["main"]

Now, this script works when I run the main() function while being in the inner my_application directory. But as soon as the function is run from somewhere else, e.g. by running run.py or using the console script, mplayer complains that it can't find sound.mp3:

Cannot open file 'sound.mp3': No such file or directory

How can I make sure that mplayer finds sound.mp3, no matter the directory I'm in?


Solution

  • If you are using setuptools, you can use pkg_resources to retrieve the correct path to the file:

    import pkg_resources
    
    class Sound():
        def __init__(self):
            sound_path = pkg_resources.resource_filename(
                'my_application', 'sound.mp3')
            self.cmd = ['mplayer', sound_path]
    
        ...