Introduction

Hooks make it easy to tweak, replace, or extend coma.

Types of Hooks

At the highest level, hooks belong to one of two types:

parser

Parser hooks are called when a command is register()ed and are meant to add_arguments() to the underlying ArgumentParser bound to the command.

invocation

Invocation hooks are called by wake() if, and only if, the command to which they are globally initiate()d or locally register()ed is invoked.

Invocation hooks further belong to one of three sub-types:

config

A config hook is meant to initialize or affect the config objects that are globally initiate()d or locally register()ed to a command.

init

An init hook is meant to instantiate or affect the command itself.

Warning

For function-based commands, the function is internally wrapped in another object, and it is this wrapper object that an init hook receives.

run

A run hook is meant to execute or surround the execution of the command.

For all three hook sub-types above (config, init, and run), each is further split into three sub-sub-types:

pre

A pre hook is called immediately before a main hook as a way to add additional behavior.

main

A main hook is generally meant to perform the bulk of the work.

post

A post hook is called immediately after a main hook as a way to add additional behavior.

Altogether, there are 9 invocation hooks.

Hook Pipeline

As stated above, parser hooks are called at the time a command is register()ed, whereas the invocation hooks are called if, and only if, the corresponding command is invoked.

The following keywords are used to initiate(), register(), and/or forget() hooks:

Type

Sub-Type

Sub-Sub-Type

Keyword

parser

N/A

N/A

parser_hook

invocation

config

pre

pre_config_hook

main

config_hook

post

post_config_hook

init

pre

pre_init_hook

main

init_hook

post

post_init_hook

run

pre

pre_run_hook

main

run_hook

post

post_run_hook

The invocation hook pipeline consists of calling all the invocation hooks, in the order listed here, one immediately following the other, with no other code in between. In other words, the invocation hooks make up the entirety of the hook pipeline.

Default Hook Pipeline

Rather than being hard-coded, coma’s default behavior is, almost entirely, a result of having certain specific default hooks initiate()d. The upshot is that there is almost no part of coma’s default behavior that cannot be tweaked, replaced, or extended through clever use of hooks.

The default hooks are:

parser

The default parser_hook is coma.hooks.parser_hook.default(). This hook uses add_argument() to add, for each config, a parser argument of the form --{config_id}-path where {config_id} is the config’s identifier. This enables an explicit file path to the serialized config to be specified on the command line.

pre config

N/A

main config

The default config_hook is coma.hooks.config_hook.default(). This hook does a lot of the heaving lifting for manifesting coma’s default behavior regarding configs. In short, for each config, this hook:

  • Attempts to load the config from file. This can interact with the default parser_hook.

  • If the config file isn’t found, a config object with default attribute values is instantiated, and the default config object is serialized.

Note

YAML is used for serialization by default (since it is the only format that omegaconf supports), but coma also natively supports JSON. See here for full details on configuration files.

post config

The default post_config_hook is coma.hooks.post_config_hook.default(). This hook is responsible for overriding config attribute values with any that are specified on the command line in omegaconf’s dot-list notation. See here for full details on command line overrides.

pre init

N/A

main init

The default init_hook is coma.hooks.init_hook.default(). This hook instantiates the command object by invoking it with all configs given, in order, as positional arguments.

post init

N/A

pre run

N/A

main run

The default run_hook is coma.hooks.run_hook.default(). This hook calls the command object’s run() method with no parameters.

post run

N/A

Note

For each of the default hooks, factory functions are provided that can create new variations on these defaults. For example, coma.hooks.run_hook.factory() can be used to change the command execution method name from run() to something else. See here to explore all factory options.

Note

If you are finding that the factory functions for the parser hook, main config hook, and/or post config hook are insufficient, consider making use of the many config-related utilities found here to help you in writing your own custom hooks.

Global and Local Hooks

Hooks can be initiate()d globally to affect coma’s behavior towards all commands or register()ed locally to only affect coma’s behavior towards a specific command.

Warning

Local hooks are appended to the list of global hooks. Local hooks do not override global hooks. To override a global hook, use register() in conjunction with forget(). See here for details.