Python scripting#

Overview#

This section explores intermediate Python topics to improve our technique at specific linux/IoT scripting tasks.

We’ll explore:

  • Passing terminal arguments to a script

  • __main__ and top-level environment

  • Running modules as scripts using __main__

  • Tip for managing gpio dependencies

Passing Script Arguments#

It’s possible to pass command line arguments to a Python script directly from your shell:

$ python myscript.py first 2 True

The arguments passed are first, 2 and True .

sys.argv#

The Python sys module provides access to these arguments via sys.argv:

  • sys.argv is a Python list of arguments.

# myscript.py

print(f"Argument List: {sys.argv}")

Output:

$ python myscript.py first 2 True

Argument List: ['myscript.py', 'first', '2', 'True']

Notice the following:

  • The first element in the list is the name of the script.

  • Arguments are available as strings.

Unfortunately, we can’t trust that the user will always pass arguments in the correct order and using appropriate data types. We would still need to parse the arguments and make sure they are valid.

Fortunately, there is a built-in module that can help us do that.

argparse#

argparse is a built-in module that makes it easy to write user-friendly command-line interfaces.

Once the script defines what arguments are required, argparse will figure out how to parse those out of sys.argv. The argparse module also automatically generates help and usage messages, and issues errors when users give the program invalid arguments.

For a basic tutorial of argparse, see this page.

In its simplest form, argparse must be imported and a parser must be instantiated:

# myscript.py

import argparse

parser = argparse.ArgumentParser()
args = parser.parse_args()
print(args)

However, this will generate an error because we must tell argparse what argument flags and what data types to parse.

$ python myscript.py first 2 True

usage: myscript.py [-h]
myscript.py: error: unrecognized arguments: first 2 True

To “teach” argparse how to parse an argument we use the command parser.add_argument()

# myscript.py
import argparse

parser = argparse.ArgumentParser()

parser.add_argument("word", type=str)
parser.add_argument("number", type=int)
parser.add_argument("toggle", type=bool)

args = parser.parse_args()

print(args)
print(args.word)
print(args.number)
print(args.toggle)
$ python myscript.py first 2 True

Namespace(word='first', number=2, toggle=True)
first
2
True

Notice how in the example above, all arguments were positional, which makes them mandatory. In other words, the order in which they are passed determines which variable they were being assigned to.

It’s also possible to make arguments optional. In this case, they must be specified with the correct “Flag”.

# myscript.py
import argparse

parser = argparse.ArgumentParser()

parser.add_argument("--word", type=str)
parser.add_argument("--number", type=int)
parser.add_argument("--toggle", type=bool)

args = parser.parse_args()

print(args)
print(args.word)
print(args.number)
print(args.toggle)
$ python myscript.py --word first --number 2

Namespace(word='first', number=2, toggle=None)
first
2
None

argparse References#

Top-level environment#

Why include a if __name__ == "__main__": in your script?

There are two ways of executing Python code. Depending on how the code is executed, the global string variable __name__ will take one of two values:

  1. If the script is run by the Python interpreter :

    • __name__ has the value of __main__

  2. Importing script as a separate Python module:

    • __name__ has the value of the module name.

Let’s illustrate these two cases below.

TL:DR

Executing as a Script#

Consider the following script:

# file my_script.py

print("Inside my_script.py, variable `__name__` is: ", __name__)

Executing this file with the Python interpreter:

$ python my_script.py

# Output
# Inside my_script, variable `__name__` is: __main__

Executing as a Module#

Consider a new file:

# file your_script.py

print("Inside your_script.py, variable `__name__` is: ", __name__)

Now modify my_script.py to import your_script.py:

# file my_script.py

import your_script

print("Inside my_script.py, variable `__name__` is: ", __name__)

When a file is imported as a module, it’s top-level code gets executed immediately.

When we execute my_script.py again using the Python interpreter:

$ python my_script.py

# Output
# Inside your_script, variable `__name__` is: your_script
# Inside my_script, variable `__name__` is: __main__

The first print statement came from your_script.py when it was imported by my_script.py.

Notice how inside your_script.py, the variable __name__ was the file name because it was being run as a module - from a different script (my_script.py).

Top-level Code#

All of the code that is at indentation level 0 gets executed is called the top-level.

__main__ is the name of the environment where top-level code is run.

If a module is being run as a script (as in mys_cript.py above), then __name__ is instead set to the string "__main__".

You can test whether your script is being run directly or being imported by something else by testing what __name__ evaluates to:

# another_script.py

def main():
	# Include whatever code here.

if __name__ == "__main__":
    main()  # Will only run if executing file as a script.