coma.hooks.config_hook

Config hook utilities and factories.

OverrideProtocolOrSentinels

Callable to override config attributes with command line arguments, or SENTINEL to use Override with default parameters, or None to disable overriding altogether.

Alias:

alias of OverrideProtocol | GeneralSentinel | None

initialize_factory(config_id: str, raise_on_fnf: bool = False) Callable[[T], T | None][source]

Factory for creating an invocation hook with config_hook semantics.

Specifically, initializes the Config corresponding to config_id from amongst the configs (or supplemental configs) in coma.hooks.base.HookData.parameters.

The initialization leverages initialize(). The file_path parameter to initialize() is derived by calling get_file_path() on the current value of the persistence_manager object, except if config_id corresponds to a config where is_serializable() is False, which is never initialized from file.

If loading from file fails due to a FileNotFoundError, the error is re-raised if raise_on_fnf is True. If raise_on_fnf is False, a config with default values is initialized and the missing file is silently ignored.

Example

Fail fast when encountering a FileNotFoundError:

coma.command(..., config_hook=initialize_factory(..., raise_on_fnf=True))
Parameters:
  • config_id (ConfigID) – The identifier of the config to initialize.

  • raise_on_fnf (bool) – If True, raises a FileNotFoundError if the config file was not found. If False, a config object with default values is initialized instead of failing outright.

Returns:

A hook with partial config_hook semantics.

Return type:

Hook

Raises:
  • KeyError – If config_id does not match any known config or supplemental config.

  • FileNotFoundError – If raise_on_fnf is True and the config file was not found.

  • Others – As may be raised by the underlying omegaconf handler or by initialize().

write_factory(config_id: str, *, instance_key: str | None = None, resolve: bool = False, overwrite: bool = False) Callable[[T], T | None][source]

Factory for creating an invocation hook with partial config_hook semantics.

Specifically, serializes the instance_key instance of the Config corresponding to config_id from amongst the configs (or supplemental configs) in coma.hooks.base.HookData.parameters.

The serialization leverages write(), with instance_key and resolve passed directly to it. The file_path parameter to write() is derived by calling get_file_path() on the current value of the persistence_manager object, except if config_id corresponds to a config where is_serializable() is False, which is never written to file.

If the destination file already exists, new content is only written if overwrite is True.

Example

Always write a specific config instance, rather than the latest:

coma.command(..., config_hook=write_factory(..., instance_key="MY KEY"))
Parameters:
  • config_id (ConfigID) – The identifier of the config to serialize.

  • instance_key (InstanceKey, optional) – The specific Config instance to serialize. If None, the latest instance is used.

  • resolve (bool) – Passed directly to write().

  • overwrite (bool) – Whether to overwrite the file content whe the destination file already exists.

Returns:

A hook with partial config_hook semantics.

Return type:

Hook

Raises:
  • KeyError – If config_id does not match any known config or supplemental config.

  • Others – As may be raised by the underlying omegaconf handler or by write().

override_factory(config_id: str, instance_key: str | None = None, override: OverrideProtocol | GeneralSentinel | None = GeneralSentinel.token) Callable[[T], T | None][source]

Factory for creating an invocation hook with partial config_hook semantics.

Specifically, overrides the instance_key instance of the Config corresponding to config_id from amongst the configs (or supplemental configs) in coma.hooks.base.HookData.parameters with command line arguments.

Leverages Override, with instance_key passed directly to it. If override has value SENTINEL, an Override with default parameters is used. Slight variations can be declared by directly setting override to a specific instance of Override. Alternatively, entirely custom implementations can also be provided so long as the provided object is a Callable with a signature that adheres to the OverrideProtocol. If override is None, returns immediately without performing any override.

Example

Change separator to "~":

coma.command(..., config_hook=override_factory(..., override=Override(sep="~")))
Parameters:
  • config_id (ConfigID) – The identifier of the config to override.

  • instance_key (InstanceKey, optional) – The specific Config instance to override. If None, the latest instance is used.

  • override (OverrideProtocolOrSentinels) – Callable to override config attributes with command line arguments; or SENTINEL to use Override with default parameters; or None to disable override altogether.

Raises:
  • KeyError – If config_id does not match any known config or supplemental config.

  • Others – As may be raised by the underlying omegaconf handler or by override.

Returns:

A hook with partial config_hook semantics.

Return type:

Hook

default_factory(*config_ids: str, raise_on_fnf: bool = False, override_instance_key: str | None = None, override: OverrideProtocol | GeneralSentinel | None = GeneralSentinel.token, skip_write: Container[str] | None = None, write: bool = True, write_instance_key: str | None = 'BASE', resolve: bool = False, overwrite: bool = False) Callable[[T], T | None][source]

Factory for creating an invocation hook with config_hook semantics.

Note

If config_ids is empty, defaults to all registered configs for the command being executed. In other words, only specify config_ids explicitly to limit the factory to only those configs.

Assumptions made in designing this config hook implementation:

  1. Configs are declarative. They follow the following declaration hierarchy:

    CLI override > file (if any) > code default.

  2. Configs are, by default, useful.

    This means, by default, declared configs (both standard and supplemental) are loaded (where “loaded” here means loaded based on the entire declarative hierarchy). However, the CLI override can be disabled by setting override to None.

  3. Persistence of configs is typically desirable.

    This means that, by default, configs are serialized (to enable the middle of the declarative hierarchy), but skipping serialization is made easy (use skip_write to disable for particular configs, or set write is False to disable for all configs).

  4. Configs often fall into neat groups that should be treated a particular way.

    For example, one group skips overriding, while another skips serializing. Both config_ids and skip_write enable such group declarations.

This default factory is equivalent to:

1. Calling initialize_factory() on the specified configs, passing in raise_on_fnf directly.

2. Then, calling override_factory(), passing in override_instance_key, and override directly.

3. Then, only if write is True, calling write_factory() on all specified configs not also in skip_write, passing in write_instance_key, resolve, and overwrite directly.

Example

Override only one group and configs and serialize only another group:

coma.command(
    ...,
    config_hook=(
        default_factory("override", "only", "configs", write=False),
        default_factory("write", "only", "configs", override=None),
    )
)
Parameters:
Returns:

A hook with config_hook semantics.

Return type:

Hook

Raises:

Various – As may be raised by the underlying components.

preload(data: InvocationData, *config_ids, limited: bool = False, raise_on_fnf: bool = False, override: OverrideProtocol | GeneralSentinel | None = GeneralSentinel.token) None[source]

Convenience wrapper around coma.hooks.config_hook.default_factory().

Configs are declarative. They follow the following declaration hierarchy: CLI override > file (if any) > code default. “Load” here means loading based on the entire declarative hierarchy. “Pre” here refers to the idea that this procedure is typically called in a user-defined pre_config_hook to load some configs (typically supplemental configs) as a preprocessing step before the main config_hook.

Preloading never serializes any of the configs. CLI is enabled by default, but can be disabled by setting override to None. If limited is True, limit override exclusivity checks to just the config_ids. Otherwise, perform exclusivity checks on all configs in data.parameters (which requires initializing all configs).

Example

Preload some supplemental configs in pre_config_hook:

def pre_config_hook(data: InvocationData) -> InvocationData:
    preload_ids = ["supplemental_cfg_1", "supplemental_cfg_2"]
    preload(data, *preload_ids)
    cfgs = data.parameters.select(*preload_ids)
    do_something_with(cfgs)

    # This prevents further processing of these configs.
    data.parameters.delete(*preload_ids)

@command(
    name="command_name",
    pre_config_hook=pre_config_hook,
    ...,
    supplemental_cfg_1=...,
    supplemental_cfg_2=...,
)
def my_cmd(...):
    ...
Parameters:
Returns:

data is modified in-place and preloaded configs should be retrieved directly from it.

Return type:

None

Raises: