Running modules from the command line

In Chapter 2, Writing Your First Modular Program, we saw your system's main program is often named main.py and typically has the following structure:

def main():
    ...

if __name__ == "__main__":
    main()

The __name__ global variable will be set to the value "__main__" by the Python interpreter when the user runs your program. This has the effect of calling your main() function when the program is run.

There is nothing special about the main.py program, however; it's just another Python source file. You can take advantage of this to make your Python modules executable from the command line.

Consider, for example, the following module, which we will call double.py:

def double(n):
    return n * 2

if __name__ == "__main__":
    print("double(3) =", double(3))

This module defines some functionality, in this case a function named double(), and then uses the if __name__ == "__main__" trick to demonstrate and test the module's functionality when it is run from the command line. Let's try running this module to see how it works:

% python double.py 
double(3) = 6

Another common use for a runnable module is to allow the end user to directly access the module's functionality from the command line. To see how this works, create a new module named funkycase.py, and enter the following into this file:

def funky_case(s):
    letters = []
    capitalize = False
    for letter in s:
        if capitalize:
            letters.append(letter.upper())
        else:
            letters.append(letter.lower())
        capitalize = not capitalize
    return "".join(letters)

The funky_case() function takes a string and capitalizes every second letter. If you wanted to, you could import this module and then access this function from within your program:

from funkycase import funky_case
s = funky_case("Test String")

While this is useful, we also want to let the user run the funkycase.py module as a standalone program, directly converting the supplied string to funky-case and printing it out to the user can see it. To do this, we can use the if __name__ == "__main__" trick along with sys.argv to extract the string supplied by the user. We can then call the funky_case() function to convert this string to funky-case and print it out. To do this, add the following code to the end of your funkycase.py module:

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("You must supply exactly one string!")
    else:
        s = sys.argv[1]
        print(funky_case(s))

Also, add the following to the top of your module:

import sys

You can now run this module directly as if it was a standalone program:

% python funkycase.py "The quick brown fox"
tHe qUiCk bRoWn fOx

In this way, funkycase.py acts as a kind of chameleon module. To other Python source files, it appears as just another module that can be imported and used, while to the end user it looks like a standalone program that can be run from the command line.

Tip

Note that if you want to make a module executable from the command line, you aren't limited to just using sys.argv to accept and process the arguments supplied by the user. The excellent argparse module in the Python Standard Library allows you to write Python programs (and modules) that accept a wide range of inputs and options from the user. If you haven't used this module before, do check it out.

There is one issue to be aware of when you create a module that can be run from the command line: if your module uses relative imports, your imports will fail with an attempted relative import of non-package error when you run it directly using the Python interpreter. This error occurs because a module forgets about its position within the package hierarchy when it is run from the command line. As long as your module doesn't use any command-line arguments, you can get around this problem by using Python's -m command-line option, like this:

python -m my_module.py

However, if your module does accept command-line arguments, then you will need to replace your relative imports so that this problem doesn't occur. There are workarounds, but they are kludgy and not recommended for general use.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.34.226