Zip and ship, make an executable zipfile of your py project

Posted by Bob on Sun 25 December 2016 in Packages

Get started

First of all, new in version 3.5 is zipapp which makes this easier. As not everybody is on this version yet, I will show the manual way to do this.

We're going to use the code of our last post: Get a weekly digest from a Pelican blog.

Step by step

OK here we go:

$ git clone https://github.com/pybites/blog_code zip-example
Cloning into 'zip-example'...
remote: Counting objects: 22, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 22 (delta 4), reused 22 (delta 4), pack-reused 0
Unpacking objects: 100% (22/22), done.
Checking connectivity... done.

$ cd zip-example/pybites_digest/
$ mkdir archive && cd $_
$ cp ../digest.py __main__.py

# Note that where I say python3 and pip3 for you it might be python and pip

$ pip3 install -r ../requirements.txt --target=packages
Collecting feedparser==5.2.1 (from -r ../requirements.txt (line 1))
Installing collected packages: feedparser
Successfully installed feedparser-5.2.1

$ touch packages/__init__.py
$ ls *
__main__.py
packages:
__init__.py         <dependencies>

# edit the main script to use the locally installed package (doing 'in place' edit)
$ perl -pi -e 's/import feedparser/import packages.feedparser as feedparser/g' __main__.py

# zip it up
$ zip my_script.zip -r *
adding: __main__.py (deflated 55%)
adding: packages/ (stored 0%)
adding: packages/__init__.py (stored 0%)
adding: packages/__pycache__/ (stored 0%)
adding: packages/__pycache__/feedparser.cpython-35.pyc (deflated 59%)
adding: packages/feedparser-5.2.1.dist-info/ (stored 0%)
adding: packages/feedparser-5.2.1.dist-info/DESCRIPTION.rst (stored 0%)
adding: packages/feedparser-5.2.1.dist-info/INSTALLER (stored 0%)
adding: packages/feedparser-5.2.1.dist-info/METADATA (deflated 64%)
adding: packages/feedparser-5.2.1.dist-info/metadata.json (deflated 58%)
adding: packages/feedparser-5.2.1.dist-info/RECORD (deflated 40%)
adding: packages/feedparser-5.2.1.dist-info/top_level.txt (stored 0%)
adding: packages/feedparser-5.2.1.dist-info/WHEEL (stored 0%)
adding: packages/feedparser.py (deflated 74%)

$ echo '#!/usr/bin/env python3' > my_script
$ cat my_script.zip >> my_script
$ chmod ug+x my_script

# to prove it shows the feedparser package is not installed in my main py3 installation
$ python3
Python 3.5.1 |Anaconda 4.0.0 (x86_64)| (default, Dec  7 2015, 11:24:55) 
[GCC 4.2.1 (Apple Inc. build 5577)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import feedparser
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named 'feedparser'
>>>

# yet it works with the zipped package :)
$ ./my_script 
Get a weekly digest from a Pelican blog
http://pybit.es/blog-digest.html
In this post a script we use to get a weekly digest of our posts.
--

2016 py articles and useful books
http://pybit.es/py-articles-books2016.html
Some of my Python articles I posted on my blog this year and useful books
...
...

# I can put it in my $HOME/bin now as well:

$ cp my_script ~/bin/pybites_digest
$ which pybites_digest
/Users/bbelderb/bin/pybites_digest
$ pybites_digest
Zip and ship, make an executable zipfile of your py project
http://pybit.es/zip-and-ship.html
In this post I show an example how you can distribute your code as an executable zipfile, a neat trick I discovered in Chapter 6 of The Hitchhiker's Guide to Python
--
...
...

Conclusion

Although I would not use this for bigger projects (you loose debugging abilities), this is still a neat way to package up and ship scripts. Consumers don't have to worry about installing dependencies / doing any pre-work.

>>> next(PyBites)

Get our 'Become a Better Python Developer' cheat sheet sent straight to your inbox by signing up for our Newsletter: