Introduction: conf.py File

pop-config uses a conf.py file to define its functionality. The conf.py file should be located in the main directory of your POP project. So let’s assume the directory for your source code is my-project, and your POP project inside it is called my_project (as created by pop-seed or pop-create). In this case, your conf.py file will be located at my-project/my_project/conf.py, and directories for POP subs for your project will appear next to the conf.py (in the same directory.)

One conf.py exists per POP project. conf.py can contain four Python dictionaries: CONFIG, CLI_CONFIG, SUBCOMMANDS and DYNE. Each dictionary serves a specific purpose. Between them you can define how the command-line arguments are presented, all configuration defaults, help documentation, etc. Here are the purposes of each dictionary:

Dictionaries Overview

DYNE:

The DYNE dictionary is used to allow your POP project to define dynamic names. Dynamic names are plugin subsystems that are shared across multiple projects and dynamically discovered. This allows you to, for example, have one “super-command” which can find a bunch of plugins that were installed by multiple different Python projects. All the plugins are organized under a dyne name. Each project maps the dyne name to a path inside its source code. The plugins in this directory are made available to other projects when the dyne is added via a call to hub.pop.sub.add(dyne_name="foo"). Then hub.foo.plugin_name_1, hub.foo.another_plugin will be available on the hub. You can also introspect on the plugins available via for plugin in hub.foo:, for example.

CLI_CONFIG:

CLI_CONFIG is a dictionary that defines command-line arguments for your application. The command line arguments defined here will be accessible at hub.OPT.pop_project_name.foo or hub.OPT["pop_project"]["foo"] (assuming an option of --foo), for example. Each POP project has a single namespace for command-line options. The keys and values used in CLI_CONFIG will be very familiar if you have used the argparse module in Python.

Please see the CLI_CONFIG Dictionary section for more details on how to use CLI_CONFIG.

CONFIG:

CONFIG is a dictionary that defines “configuration” for your application, which are settings, but ones that are not available on the command-line. Configuration defined in CONFIG, while not settable on the command-line, is still accessible via hub.OPT.

Where are CONFIG settings sourced from, if not from the command-line? Typically, they are simply default values, potentially overridable via a pop-config YAML configuration file.

Please see the CONFIG Dictionary section for more details on how to use CONFIG.

SUBCOMMANDS:

Think of SUBCOMMANDS as a companion to CLI_CONFIG. SUBCOMMANDS allows you to define higher-level actions on the command-line, each with their own separate arguments. For example, you may have mycmd list as well as mycmd commit. The subcommand is specified as just a literal string. Command-line arguments defined in CLI_CONFIG can be specified as being specific to a subcommand or can be made available to all subcommands.

Please see the SUBCOMMANDS Dictionary section for more details on subcommands.

Steps for Using pop-config

To use pop-config, at the bare minimum you will want to create a conf.py for your project at my-project/my_project/conf.py. It’s important to note that there is only one conf.py per POP project, and only one set of config per conf.py.

In conf.py, you will define CLI_CONFIG to specify all command-line options for your application. Here is an example of a CLI_CONFIG definition:

CLI_CONFIG = {
    "force": {"options": ["--force"], "action": "store_true", "default": False},
    "nopush": {"options": ["--nopush"], "action": "store_true", "default": False},
    "prod": {"options": ["--prod"], "action": "store_true", "default": False},
    "db": {"options": ["--db"], "action": "store_true", "default": False},
    "release": {"positional": True},
}

Then, somewhere in the startup code of your command, you will have something similar to the following Python code:

hub.pop.sub.add("my_project")
# or hub.pop.sub.add(dyne_name="my_project") if you are using a dynamic name
hub.pop.config.load(["my_project"], cli="my_project")

After this last command finishes, the config defined in conf.py as well as any user-specified arguments will be available on the hub at hub.OPT["my_project"].option_name. If you defined any subcommands via SUBCOMMANDS, you will be able to determine the subcommand specified by inspecting the hub.SUBPARSER variable, which is a string that specifies the subcommand. Any subcommand-specific options will be accessible at hub.OPT["my_project"].option_name – there is no special hierarchy for subcommand options – they are just mapped to the same place as regular options.

Once this initialization is done, then various parts of your application can look at hub.OPT["my_project"] and use the settings found to influence its behavior. Because hub.OPT is globally available to all POP functions, you do not need to pass around these options as arguments to functions and can read them from a central, consistent location on the hub.