Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Being fairly new to python I only recently discovered the ability to directly execute a .zip file by placing a __main__.py file at the top of the file. This works great for python code, but can I bundle other types of files and access them with my scripts? If so, how?

My ultimate goal would be to bundle some image files along with the python code in a single .zip file, then be able to use those images within the app without having to extract them to disk. I also would like to bundle a copyright notice, release notes, etc so that the entire app and its data files is in a single zip that can be executed without having to extract it somewhere.

print pkg_resources.resource_string(__name__, 'README.txt') im = Image.open(pkg_resources.resource_stream('app', 'im.png')) im.rotate(45).show()

Where zipfile contains:

|-- app | |-- im.png | `-- __init__.py |-- README.txt `-- __main__.py

To make zipfile executable, run:

$ echo '#!/usr/bin/env python' | cat - zipfile > program-name
$ chmod +x program-name

To test it:

$ cp program-name /another-dir/
$ cd /another-dir && ./program-name

At least on my Linux box there is no open filehandle or mapped memory by the process to its own zipfile, so presumably there is no way to "magically" access it.

However, creating your own access is not that hard. Create a __main__.py like so:

import os, zipfile
me = zipfile.ZipFile(os.path.dirname(__file__), 'r')
f = me.open('other.txt')
print f.read()
f.close()
me.close()

Edit: Somewhat terse, that. For completeness:

$ echo "Hello ZIP" > other.txt
$ zip testo.zip __main__.py other.txt
$ python testo.zip
Hello ZIP
                It never occurred to me to re-open the currently executing zipfile. Cool. Unfortunately, when I run my script on OSX __file__ is None. I think this is a step in the right direction though.
– Bryan Oakley
                Mar 18, 2011 at 18:21
                @Bryan Oakley: sys.argv[0] contains the zipfile path if the first line in the zipfile is #!/usr/bin/env python or similar.
– jfs
                Mar 18, 2011 at 20:20
                this only works if I put my files in a package, which means it won't work for a README.txt or COPYRIGHT.txt file at the root of the zip file. That's not a critical issue, but I would like to be able to put some files alongside the main.py at the top of the zip file hierarchy.
– Bryan Oakley
                Mar 18, 2011 at 19:15
                Combell: I wish that were true. At least with my test .zip file on OSX and python 2.6, main is undefined.
– Bryan Oakley
                Mar 18, 2011 at 19:49
                @Bryan Oakley: the zipfile is added as the first item in sys.path therefore you should always be able to import __main__. I've test my answer and README.txt stored along-side __main__.py in the zip-file can be read just fine stackoverflow.com/questions/5355694/…
– jfs
                Mar 18, 2011 at 20:02

pkgutil.get_data(package, resource) takes the name of a package and a resource. That means you have to put your data files inside a package within the zip file.

So for example a zip file containing:

__main__.py
zippeddata/__init__.py
zippeddata/data.txt

The __init__.py file can be empty or just a comment, but you need one to make zippeddata importable.

Then in __main__.py you just call:

data = pkgutil.get_data('zippeddata', 'data.txt')
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.