Tip

Hover your cursor over any code block in this tutorial, and a clipboard will appear. Click it to copy the contents of the code block.

Prerequisites

This tutorial assumes that you have completed the earlier tutorial: Create and Launch a Basic Application with Hydra

Add a Command Line Interface to Our Application#

In this tutorial we will update our project so that it can be configured and launched from a command line interface (CLI), using Hydra.

In the last section of the tutorial, we

  • Defined a task function

  • Created a config for that task function

  • Ran the task function via hydra_zen.launch(Config, task_function, overrides=<...>)

In this section, we need to add our config to Hydra’s config-store; this enables Hydra to generate a CLI from this config.

Modifying Our Project#

Open my_app.py in your editor. We will make the following modifications to it:

  1. Use hydra_zen.ZenStore to store our config locally.

  2. Add a __main__ clause to our my_app.py script so that the script runs our task function.

  3. Within __main__ populate Hydra’s global config store so that Hydra can generate a CLI using our configs.

  4. Use hydra_zen.zen() to wrap the task function and to generate the CLI.

Modify your script to match this:

Contents of my_app.py:#
from hydra_zen import builds, zen, ZenStore

# The same task function as before
def task_function(player1: str, player2: str):
    with open("player_log.txt", "w") as f:
        f.write("Game session log:\n")
        f.write(f"Player 1: {player1}\n" f"Player 2: {player2}")

    return player1, player2

Config = builds(task_function, populate_full_signature=True)

# 1) Create a local config store and store our config
store = ZenStore()
store(Config, name="my_app")

# 2) Adding our __main__ clause to our script.
#    Executing `python my_app.py [...]` will generate a CLI for our running
#    our task function
if __name__ == "__main__":
    # 3) We need to add the configs from our local store to Hydra's
    #    global config store
    store.add_to_hydra_store()

    # 4) hydra_main generates a CLI based off of the config
    #    stored under the name "my_app", and will run
    #    `task_function`
    zen(task_function).hydra_main(config_name="my_app",
                                  version_base="1.1",
                                  config_path=None,
                                  )

Launching Our Application from the Command Line#

With the above modifications to my_app.py complete, we can launch our application from the command line. The following will launch a job with mario and luigi as the names for player 1 and player 2, respectively.

Open your terminal in the same directory as my_app.py. We can view the configurable aspects of our application using the --help command; run the following:

Checking the configurable components of our app. (We will add configuration groups in a later lesson.)#
$ python my_app.py --help
my_app is powered by Hydra.

== Configuration groups ==
Compose your configuration from those groups (group=option)



== Config ==
Override anything in the config (foo.bar=value)

player1: ???
player2: ???

See that our app requires that we configure two fields: player1 and player2. Let’s configure these fields with the string values "mario" and "luigi", respectively. In your console execute the following command:

Launching our application from the command line#
$ python my_app.py player1=mario player2=luigi

Tip

You can add tab-completion to your application’s command line interface. This is helpful once you start writing applications that have many configurable components.

To inspect the log written by our application, open a Python terminal in the same directory as my_app.py and define the following function for reading files

>>> from pathlib import Path
>>> def print_file(x: Path):
...     with x.open("r") as f:
...         print(f.read())

Getting the directory containing the output of this job:

>>> *_, latest_job = sorted((Path.cwd() / "outputs").glob("*/*"))
>>> latest_job  # changes based  on reader's date, time, and OS
WindowsPath('C:/outputs/2021-10-21/12-58-13')

Print the contents of player_log.txt and verify that it matches with how we ran our program:

>>> print_file(latest_job / "player_log.txt")
Game session log:
Player 1: mario
Player 2: luigi

Voilà! As demonstrated, our simple application can now be configured and launched from the command line. It should be noted that we can still launch our app from a Python console, using launch(), as we did in the previous tutorial.

Streamlining Our Code#

hydra_zen.ZenStore has auto-config capabilities and it can be used as a decorator. This enables us to both create and store a config for our task function in a single line.

Streamlined version of my_app.py:#
from hydra_zen import zen, ZenStore

store = ZenStore()

@store(name="my_app")
def task_function(player1: str, player2: str):
    with open("player_log.txt", "w") as f:
        f.write("Game session log:\n")
        f.write(f"Player 1: {player1}\n" f"Player 2: {player2}")

    return player1, player2

if __name__ == "__main__":
    store.add_to_hydra_store()
    zen(task_function).hydra_main(config_name="my_app",
                                  version_base="1.1",
                                  config_path=None,
                                  )

Here, applying @store("my_app") to task_function is equivalent to

store(builds(task_function, populate_full_signature=True), name="my_app")

Reference Documentation#

Want a deeper understanding of how hydra-zen and Hydra work? The following reference materials are especially relevant to this tutorial section.

Attention

Cleaning Up: To clean up after this tutorial, delete the outputs directory that Hydra created upon launching our application.