Radoslaw Smigielski

19 July 2019

Execute Python modules and compressed modules

by Radosław Śmigielski

Why?

It was somehow mysterius to me how commands like below wotk?

How does Python interpreter know where to find executable code?

  echo '{"json":"obj"}' | python3 -m json.tool
  python3 -m http.server --directory /tmp/http --bind 127.0.0.1 8001
  python3 -m zipfile -c /tmp/zip.zip /etc/fstab
  python3 -m venv /tmp/venv
  python3 -m unittest

So after a little bit of googling I found PEP-0441 which says:

Python has had the ability to execute directories or ZIP-format archives as scripts since version 2.6 [1]. When invoked with a zip file or directory as its first argument the interpreter adds that directory to sys.path and executes the main module.

How?

Executable module

Let’s start with python -m module.name option. Official Python3 doc says:

Searches sys.path for the named module and runs the corresponding .py file as a script.

Unfortunately that doc sentenence doesn’t specify what is that “corresponding .py file”. And as it tunedned out it needs to be __main__.py file, which is an module entry point. So here is the example of empty module which can be called as executable.

Two files in module directory:

$ ls -l module/
total 12
-rw-rw-r--. 1 radek radek  65 Jul 19 16:06 __init__.py
-rw-rw-r--. 1 radek radek  96 Jul 19 16:05 __main__.py

And files content as follow:

# file: module/__init__.py
print("I am package {} from file {}".format(__name__, __file__))

# file: module/__main__.py
if __name__ == "__main__":
    print("I am package {} from file {}".format(__name__, __file__))

So now, let’s execute our new module:

$ python -m module
I am package module from file module/__init__.py
I am package __main__ from file /tmp/module/__main__.py

Compressed executable module

This may be a little bit similar to Java .jar files and should make modules distribution easier.

Let’s compress our module, I am going to use zipfile module but it can be zip in any other way.

$ python3 -m zipfile -c  module.zip module
$ python3 -m zipfile --list compressed_module.zip
File Name                                             Modified             Size
__init__.py                                    2019-07-19 16:06:20           65
__main__.py                                    2019-07-19 16:05:20           96

Now we can execute that compressed module:

$ python3 compressed_module.zip
I am package __main__ from file compressed_module.zip/__main__.py

And it works!

tags: Python